So Leute, ich hab mal die "reine imperative" und die tabellengesteuerte Variante implementiert (haben beide auf Anhieb funktioniert
)
Achso: die Automaten lesen eine Kommazahl und ersetzten das "," zu "-".
Delphi-Quellcode:
unit Imperative;
interface
type
state = (sStart, sFrac, sTrunc, sStop);
type
DEA_imperative =
class
private
fInput,
fOutput:
string;
fPos: BYTE;
fState: state;
public
constructor _create(
const input:
string);
destructor _destroy;
procedure _execute;
function _getOutput:
string;
end;
implementation
constructor DEA_imperative._create(
const input:
string);
begin
fInput := input + #0
end;
destructor DEA_imperative._destroy;
begin
end;
procedure DEA_imperative._execute;
begin
fPos := 1;
fState := sStart;
fOutput := '
';
while fState <> sStop
do begin
case fState
of
sStart:
case fInput[fPos]
of
'
1'..'
9':
begin
fOutput := fInput[fPos];
fState := sTrunc
end
else fState := sStop
end;
sTrunc:
case fInput[fPos]
of
'
1'..'
9': fOutput := fOutput + fInput[fPos];
'
,':
begin
fOutput := fOutput + '
-';
fState := sFrac
end
else fState := sStop
end;
sFrac:
case fInput[fPos]
of
'
1'..'
9': fOutput := fOutput + fInput[fPos];
else fState := sStop
end
end;
fPos := fPos + 1
end
end;
function DEA_imperative._getOutput:
string;
begin
_getOutput := fOutput
end;
end.
Delphi-Quellcode:
unit TableControlled;
interface
type
state = (sStart, sTrunc, sTruncToFrac, sFrac, sStop);
type
DEA_tablecontrolled =
class
private
fTable:
array[sStart..sFrac]
of array[CHAR]
of state;
fInput,
fOutput:
string;
fPos: BYTE;
fState: state;
public
constructor _create(
const input:
string);
destructor _destroy;
procedure _execute;
function _getOutput:
string;
end;
implementation
constructor DEA_tablecontrolled._create(
const input:
string);
var
i: CHAR;
begin
fInput := input + #0;
for i := #0
to #225
do begin
fTable[sStart][i] := sStop;
fTable[sTrunc][i] := sStop;
fTable[sTruncToFrac][i] := sStop;
fTable[sFrac][i] := sStop
end;
fTable[sStart]['
0'] := sTrunc;
//KANN MAN DIE TABELLE "SCHÖNER" FÜLLEN?
fTable[sStart]['
1'] := sTrunc;
fTable[sStart]['
2'] := sTrunc;
fTable[sStart]['
3'] := sTrunc;
fTable[sStart]['
4'] := sTrunc;
fTable[sStart]['
5'] := sTrunc;
fTable[sStart]['
6'] := sTrunc;
fTable[sStart]['
7'] := sTrunc;
fTable[sStart]['
8'] := sTrunc;
fTable[sStart]['
9'] := sTrunc;
fTable[sTrunc]['
0'] := sTrunc;
fTable[sTrunc]['
1'] := sTrunc;
fTable[sTrunc]['
2'] := sTrunc;
fTable[sTrunc]['
3'] := sTrunc;
fTable[sTrunc]['
4'] := sTrunc;
fTable[sTrunc]['
5'] := sTrunc;
fTable[sTrunc]['
6'] := sTrunc;
fTable[sTrunc]['
7'] := sTrunc;
fTable[sTrunc]['
8'] := sTrunc;
fTable[sTrunc]['
9'] := sTrunc;
fTable[sTrunc]['
,'] := sTruncToFrac;
fTable[sTruncToFrac]['
0'] := sFrac;
fTable[sTruncToFrac]['
1'] := sFrac;
fTable[sTruncToFrac]['
2'] := sFrac;
fTable[sTruncToFrac]['
3'] := sFrac;
fTable[sTruncToFrac]['
4'] := sFrac;
fTable[sTruncToFrac]['
5'] := sFrac;
fTable[sTruncToFrac]['
6'] := sFrac;
fTable[sTruncToFrac]['
7'] := sFrac;
fTable[sTruncToFrac]['
8'] := sFrac;
fTable[sTruncToFrac]['
9'] := sFrac;
fTable[sFrac]['
0'] := sFrac;
fTable[sFrac]['
1'] := sFrac;
fTable[sFrac]['
2'] := sFrac;
fTable[sFrac]['
3'] := sFrac;
fTable[sFrac]['
4'] := sFrac;
fTable[sFrac]['
5'] := sFrac;
fTable[sFrac]['
6'] := sFrac;
fTable[sFrac]['
7'] := sFrac;
fTable[sFrac]['
8'] := sFrac;
fTable[sFrac]['
9'] := sFrac
end;
destructor DEA_tablecontrolled._destroy;
begin
end;
procedure DEA_tablecontrolled._execute;
begin
fPos := 1;
fState := sStart;
fOutput := '
';
while fState <> sStop
do begin
fState := fTable[fState][fInput[fPos]];
case fState
of //ich habe es mir gespart, die einzelnen Routinen in die Tabelle zu übernehmen
sTrunc: fOutput := fOutput + fInput[fPos];
sTruncToFrac: fOutput := fOutput + '
-';
sFrac: fOutput := fOutput + fInput[fPos]
end;
fPos := fPos + 1
end
end;
function DEA_tablecontrolled._getOutput:
string;
begin
_getOutput := fOutput
end;
end.
Fazit:
mit der Case-Variante beschreibt man die Zustandsaktion UND die Übergänge!
=> Weniger Zustände.
=> Meine Meinung: Case-Var. (in DIESEM Beispiel) besser.
Zur
OOP-Variante hab ich eine Frage:
Nicht dass ich nicht mit Klassen, Vererbung, etc. umgehen kann, ich bring mir grad selbst die Konzepte bei (Probleme lösen mittels
OOP)
Wie erzeugt man am besten die Zustände?
Im Beispiel steht:
State := CoStartState.Create;
erzeugt der StartZustand automatisch den "NextState" und das geht rekursiv immer so weiter bis StopZustand?
Ist das die "gute"
OOP-Lösung?
Ich finde diese unübersichtlich und fehleranfällig.
Wie hat die
OOP-Fraktion dieses Problem gelöst?