Einzelnen Beitrag anzeigen

alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#24

Re: Automaten in Source Code

  Alt 21. Nov 2009, 20:00
Zitat von SebE:
...[/delphi]
.. //KANN MAN DIE TABELLE "SCHÖNER" FÜLLEN?
[/delphi]
Ja.
Da es dem Automaten egal ist, ob es sich um eine 1, 2 usw. handelt, kann man das drastisch verkürzen: Der DEA kennt nur Ziffern, Komma, das Terminalsymbol (Ende der Eingabe) sowie ungültige Zeichen. Da ungültige Zeichen zu einem sofortigen Abruch führen, wird die Tabelle ziemlich klein. So klein, wie das Problem, das der DEA lösen soll:
Delphi-Quellcode:
Const
  DEA : Array [symDigit..symTerminal, stStart..stDecimals] =
// symDigit , symKomma, symTerminal
{stStart }  (stDigits , stError , stError),
{stDigits}  (stDigits , stComma , stStop),
{stComma}   (stDecimals, stError , stError),
{stDecimals}(stDecimals, stError , stStop)
            );
// Natürlich implementiert man eine Funktion/Methode, die das nächste Symbol der Eingabe extrahiert,
// klassifiziert und sowohl Symbolklasse als auch das Symbol selbst zurückliefert.
So sehr Du an dem Case-Konstrukt zu hängen scheinst, es verstößt gegen diverse Grundregeln des 'clean coding' (DRY, KISS), weshalb ich das persönlich ablehne. Das ist aber Geschmackssache.

Ich stell mir nur gerade ein Case-Konstrukt mit 1700 Zuständen vor, bei dem nur bei 3 Zuständen etwas passiert...
Bei der Implementierung als Tabelle habe ich die Tabelle in einer Resource. Diese Tabelle wurde vorher vermutlich automatisch generiert und ist daher fehlerfrei. Die Implementierung selbst ist extrem kompakt und übersichtlich.

Zitat von SebE:
Nicht dass ich nicht mit Klassen, Vererbung, etc. umgehen kann...erzeugt der StartZustand automatisch den "NextState" und das geht rekursiv immer so weiter bis StopZustand?
Äh..Nein.

Zitat von SebE:
Ist das die "gute" OOP-Lösung?
Imho schon.

Zitat von SebE:
Ich finde diese unübersichtlich und fehleranfällig.
Nein. Jede Klasse, die das IAbstractState-Interface implementiert, MUSS Code für den Übergang zur nächsten Klasse implementieren, sowie den eigenen Zustand dokumentieren (IsStop, IsError). Spaghetti-Code ist hingegen unübersichtlich und fehleranfällig, da man sich jedesmal neu hineindenken muss und es ein leichtes ist, irgendwo einen Korken eingebaut zu haben (siehe unten)

Zitat von himitsu:
ich würde es dann eher so machen...
Logisch, ich wollte nur den von mir einmal gemachten Fehler (im Codebeispiel für die Abarbeitung der Tabelle) nicht implizit korrigieren.

Zitat von Reinhard Kern:
..in Assembler war das noch herrlich einfach ... war das schon fast selbstdokumentierend. Ausserdem fiel gleich auf, wenn das Programm unvollständig war, ... Natürlich ist das einer 2 fach verschachtelten Case-Struktur völlig gleichwertig. Aber wenn man das im Source-Code auch als n x m Tabelle schreiben kann, wird es sehr übersichtlich.
Siehe oben.

Zitat von SebE:
Fehleranfällig in der Hinsicht, dass man nicht SOFORT erkennt, wer was wo erzeugt.
@SebE: Ich habe deinen Code abgeschrieben. Er funktioniert nicht. Wieso?
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'..'8': fOutput := fOutput + fInput[fPos];
        else fState := sStop
        end
    end;

  fPos := fPos + 1
  end
end;

function DEA_imperative._getOutput: string;
begin
_getOutput := fOutput
end;

end.
Man muss sich in den kompletten Code eindenken und ALLES lesen, bis man den Fehler gefunden hat.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat