Autor Beitrag
Petroglyph
Hält's aus hier
Beiträge: 7

Windows Vista, Ubuntu 12.03
Delphi 7 Personal, Edition Free Pascal, Lazarus, Lua(Scite)
BeitragVerfasst: So 02.09.12 18:36 
Hallo Mitglieder des Delphiforums,

bevor ich das Problem schildere, möchte ich kurz etwas zu mir und meinen Erfahrungen mit Pascal beziehungsweise Delphi sagen.
Ich bin Schüler und habe ein Jahr lang Informatikunterricht gehabt, in dem ich mit Delphi 6 gearbeitet habe. Da der Kurs nicht genügend Schüler hatte, habe ich mir mit Hans-Georg Schumanns "Delphi for Kids" Delphi selber beigebracht. Nach Abschluss des Buches erfuhr ich vom Free Pascal Compiler.
Mit genau diesem habe ich nun eine Turingmaschine programmiert. Es ist ein Konsolenprojekt ohne grafische Benutzeroberfläche mit Lazarus. Ich entwickele es auf meinem Windows Vista Laptop.
Nun habe ich, nachdem die Maschine lief, mit der Unit "heaptrc" einen Bericht über die Speicherbenutzung erstellt und 8 nicht freigegebene Speicherblöcke entdeckt. Daraufhin fügte ich einen try-finally Block hinzu und setzte alle Arrays manuell auf die Größe 0, was allerdings nicht half. Was ich auch entdeckte ist, dass der normale "Free"-Destruktor eine Access Violation beim Schlüsselwort "inherited" produziert, während der "FreeAndNil"-Destruktor nicht dieses Verhalten aufweist.
Ich habe den Quelltext in drei Units aufgeteilt: "turing.pas" ist die Hauptunit, in der die Maschine läuft; "turinghead.pas" beinhaltet die Anweisungen für den Lese- und Schreibkopf der Maschine und "turingtable.pas" liest die Datei "turingtable.txt" aus, um so das Verhalten der Maschine zu bestimmen. In "turingtable.txt" sind nicht genutzte Zeilen mit "/" auskommentiert. Der Bericht von heaptrc ist in der Datei "memory.txt" Bei den Tests benutze ich den 4-State Busy Beaver.
Da ich Programmieren durch Versuch und Irrtum lerne, bin ich dankbar für jegliche Kritik. Ich möchte auch verstehen, was ich falsch gemacht habe und nicht einfach nur eine Lösung.
Falls der Beitrag in der falschen Abteilung ist, entschuldige ich mich.

turing.pas
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
{turing.pas}
{Program to imitate a Turing machine, based on the principles by Alan Turing.}

program Turing;

{$mode objfpc}{$H+}

uses
  sysutils,  {Used for the conversion from Integer to String.}
  TuringHead, {Unit for the head instructions.}
  TuringTable; {Unit for the instruction table.}

type
{Declarations of self made types}
  TField = Array of Char;

{Class declarations}
  TMachine = class(TObject)
    private
    Tape: TField; {The tape, from which data is read or on which data is written.}
    TapeSize: Integer; {The length of the tape at the start of the machine.}
    Head: THead; {The head, which reads, writes and moves. Look in "turinghead.pas" to see, how it works.}
    InstructionTable: TInstructionTable; {The table, which contains the instructions for the machine. Look in "turingtable.pas" to see, how it works.}
    ConstantOutput: Boolean; {If its value is "True", there will be constant output.
                              It is adjustable for performance, because the machine is much slower when it has to output data all the time.}

    procedure GetSettings(); {Ask the user for different settings.}
    procedure GetInput(); {Read the input from the user.}
    procedure TapeResize(OldSize: Integer; Direction: Char); {Expand the tape and initialize a new element.}
    procedure TapeCopy(); {Copies the elements of the array to the right.}
    procedure Display(State: Char; ReadData: Char; WriteData: Char; MoveInstruction: Char; HeadPosition: Integer); {Display the machines current status.}
  public
    constructor Create(); {Prepare the machine.}
    procedure Run(); {Run the machine.}
    destructor FreeAndNil(); {Free all objects, the machine uses.}
  protected
  published
  end;
  
var
  Machine: TMachine;
  
procedure TMachine.GetSettings();
var
  OutputType: Char;
begin
  WriteLn('If you want constant output, please type "y", if not, please type "n"!');
  ReadLn(OutputType);
  case OutputType of
    'n': ConstantOutput := False;
  'y': ConstantOutput := True
  end;
  WriteLn('Please input the start tape length! It will expand automatically, if it overflows.');
  ReadLn(TapeSize);
  if TapeSize > 0 then {Test, if the input makes sense, to prevent errors.}
    SetLength(Tape, TapeSize)
  else
    begin
      WriteLn('Please input a length greater than zero!');
    GetSettings()
  end
end;

procedure TMachine.GetInput();
var
  UserInput: String;
  Data: Char;
  HeadPosition: Integer;
begin
  WriteLn('Please input the data for the tape!');
  SetLength(UserInput, TapeSize);
  ReadLn(UserInput);
  if UserInput[TapeSize] <> '' then {Forum: Versuch falsche Eingaben abzufangen, funktioniert noch nicht.}
    begin
      HeadPosition := 0;
      while HeadPosition < TapeSize do
        begin
        Data := UserInput[HeadPosition + 1]; {The data is stored one place ahead of the current head position.}
        Head.WriteData(Tape, HeadPosition, Data);
        HeadPosition := Head.Move(HeadPosition, 'R')
      end;
      WriteLn('Thank you, these are the steps of the machine:')
  end
  else
    begin
      WriteLn('Please fill the whole tape with data!');
    GetInput()
  end
end;  

procedure TMachine.TapeResize(OldSize: Integer; Direction: Char);
var
  NewSize: Integer;
begin
  case Direction of
    'L'begin
    NewSize := OldSize + 1;
    SetLength(Tape, NewSize);
    TapeCopy(); {Copy the elements of the array, to make space for the new element.}
    Head.WriteData(Tape, Low(Tape), '0'{Initialize the new tape element with the empty data.}
  end;
    'R'begin
    NewSize := OldSize + 1;
      SetLength(Tape, NewSize);
      Head.WriteData(Tape, High(Tape), '0'{Initialize the new tape element with the empty data.}
  end
  end
end;

procedure TMachine.TapeCopy();
var
  Counter: Integer;
begin
  Counter := High(Tape);
  while Counter > 0 do
    begin
    Tape[Counter] := Tape[Counter - 1];
    Dec(Counter, 1)
  end
end;
  
procedure TMachine.Display(State: Char; ReadData: Char; WriteData: Char; MoveInstruction: Char; HeadPosition: Integer);
var
  DispHead: Integer;
begin
  DispHead := 0;
  while DispHead < Length(Tape) do {Write the data on the tape to the output.}
    begin
      Write(Tape[DispHead]);
       DispHead := Head.Move(DispHead, 'R');
    end;
  Write(' State: ' + State + ' Read: ' + ReadData + ' Write: ' + WriteData +
        ' Move: ' + MoveInstruction  + ' Head: ' + IntToStr(HeadPosition + 1)); {Constructed string to write information about the machine.}
  WriteLn('')
end;  

constructor TMachine.Create();
begin
  inherited;
  Head := THead.Create();
  InstructionTable := TInstructionTable.Create();
  GetSettings();
  GetInput()
end{TMachine.Initialize}

procedure TMachine.Run();
var
  TapeData: Char; 
  WriteData: Char;
  StateRegister: Char; 
  MoveInstruction: Char; 
  HeadPosition: Integer; 
  Running: Boolean; 
begin
  if TapeSize > 1 then
    HeadPosition := (Length(Tape) div 2) - 1 {The head starts in the middle of the tape.}
  else
    HeadPosition := 0;
  StateRegister := 'A'{This is the start register.}
  Running := True;

  while Running do
    begin
    {Get instructions for the machine.}
    TapeData := Head.ReadData(Tape, HeadPosition);
    WriteData := InstructionTable.GetData(StateRegister, TapeData, 'W');
    MoveInstruction := InstructionTable.GetData(StateRegister, TapeData, 'M');
    
    if ConstantOutput then
      Display(StateRegister, TapeData, WriteData, MoveInstruction, HeadPosition);

    Head.WriteData(Tape, HeadPosition, WriteData);

    case MoveInstruction of {Depending on the instructions, move the head.}
      'S': HeadPosition := Head.Move(HeadPosition, 'S');
      'L': HeadPosition := Head.Move(HeadPosition, 'L');
      'R': HeadPosition := Head.Move(HeadPosition, 'R')
    end;
    
    if HeadPosition > High(Tape) then
      TapeResize(Length(Tape), 'R');
    
    if HeadPosition < Low(Tape) then {If the head is farther to the left, than the tape is long, create a new field on the tape.}
    begin
      TapeResize(Length(Tape), 'L'); 
        HeadPosition := 0
      end;
    
    {Get the next state of the machine.}
    StateRegister := InstructionTable.GetData(StateRegister, TapeData, 'N');

    if StateRegister = 'H' then {This is the halting register.}
      begin
      Display(StateRegister, TapeData, WriteData, MoveInstruction, HeadPosition);
        Running := Head.Halt()
    end
    end
end{TMachine.Run}

destructor TMachine.FreeAndNil();
begin
  Head.Free();
  InstructionTable.FreeAndNil();
  SetLength(Tape, 0);
  WriteLn('The turing machine stopped. You can end the program by pressing enter.');
  inherited
end{TMachine.Stop}


{Implementation of the main program.}
begin
  Machine := TMachine.Create();
  try
    Machine.Run()
  finally
    Machine.FreeAndNil()
  end;
  ReadLn()
end{Turing}


turinghead.pas
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
{turinghead.pas}
{Unit for the head of the turing machine.}

unit TuringHead;

{$mode objfpc}{$H+}

interface

type
  THead = class(TObject)
    private
    function Stay(HeadPos: Integer): Integer; {Head does not move.}
    function MoveLeft(HeadPos: Integer): Integer; {Head moves leftwards.}
    function MoveRight(HeadPos: Integer): Integer; {Head moves rightwards.}
  public
    function Move(HeadPos: Integer; Direction: Char): Integer; {Public function, which calls 'Stay' or 'MoveLeft/Right'.}
    function ReadData(Tape: Array of Char; HeadPos: Integer): Char; {Reads data from the tape.}
    procedure WriteData(var Tape: Array of Char; HeadPos: Integer; Data: Char); {Writes data onto the tape.}
    function Halt(): Boolean; {Commands the head to stop moving.}
  protected
  published
  end;

implementation

function THead.Move(HeadPos: Integer; Direction: Char): Integer;
var
  NextPos: Integer;
begin
  case Direction of {Used this way, so only one function has to be public, not three.}
    'S': NextPos := Stay(HeadPos);
  'L': NextPos := MoveLeft(HeadPos);
  'R': NextPos := MoveRight(HeadPos)
  end;
  Move := NextPos
end{THead.Move}

function THead.ReadData(Tape: Array of Char; HeadPos: Integer): Char;
var
  Data: Char;
begin
  Data := Tape[HeadPos];
  ReadData := Data
end{THead.ReadData}

procedure THead.WriteData(var Tape: Array of Char; HeadPos: Integer; Data: Char);
begin
  Tape[HeadPos] := Data
end{THead.WriteData}

function THead.Stay(HeadPos: Integer): Integer;
var
  NextPosition: Integer;
begin
  NextPosition := HeadPos;
  Stay := NextPosition
end{THead.Stay}

function THead.MoveLeft(HeadPos: Integer): Integer;
var
  NextPosition: Integer;
begin
  NextPosition := HeadPos - 1;
  MoveLeft := NextPosition
end{THead.MovetLeft}

function THead.MoveRight(HeadPos: Integer): Integer;
var
  NextPosition: Integer;
begin
  NextPosition := HeadPos + 1;
  MoveRight := NextPosition
end{THead.MoveRight}

function THead.Halt(): Boolean;
begin
  Halt := False
end{THead.Halt}

begin
end.


turingtable.pas
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
{turingtable.pas}
{Unit for creating and accessing the instruction table.}

unit TuringTable;

{$mode objfpc}{$H+}

interface

const
  TupelLength = 5{The amount of characters, each tupel has.}

type
{Declarations of self made types}
  TTextFile = TextFile;
  TDataString = Array of String[TupelLength]; {Every tupel has its own data string.}
  TDataTable = record {The type of the record, which is used to look up the instructions for the machine.}
      State: Array of Char; {The current state of the machine.}
    Read:  Array of Char; {The read data.}
    Write: Array of Char; {The data, which has to be written onto the tape.}
    Move:  Array of Char; {The movement instruction for the head.}
    Next:  Array of Char  {The next state of the machine.}
    end;

{Class declarations}
  TInstructionTable = class(TObject)
    private
    TupelNumber: Word; {The number of seperate tupels, which are defined in the text file.}
    DataString: TDataString; {The strings, that have all the tupels.}
    DataTable: TDataTable;
    procedure FileRead();
    procedure ArrayResize(Size: Word); {Resizes all arrays, so they are only as big, as they have to be.}
    procedure TableFill(); {Fills the data table with data from the data string.}
    function GetWrite(CurrentState: Char; ReadData: Char): Char; {Fuctions, which return the wanted instruction from the table.}
    function GetMove(CurrentState: Char; ReadData: Char): Char;
    function GetNext(CurrentState: Char; ReadData: Char): Char;
  public
    constructor Create(); {Creates the data table, so it can be used.}
    function GetData(CurrentState: Char; ReadData: Char; DataType: Char): Char; {Public function to get instructions.}
    destructor FreeAndNil();
  protected
  published
  end;

implementation

procedure TInstructionTable.FileRead();
const
  FileName = 'turingtable.txt'{The text file, that contains the instructions.}
var
  Text: String[TupelLength]; {The read text, which is just one unorganised string.}
  CurrentTupel: Word; {Keeps track of the tupels.}
  DataFile: TTextFile;
begin
  SetLength(DataString, 256); {Make the array pretty big, so it gives enough space.}
  CurrentTupel := 0;
  Assign(DataFile, FileName); {Open the file.}
  Reset(DataFile);
  while not eof(DataFile) do {As long, as the procedure did not reach the end of the text file, it shall proceed.}
    begin
      ReadLn(DataFile, Text);
    if Text[1] <> '/' then {If the line starts with an '/', it is a comment and thus not necessary for the program.}
      begin
      DataString[CurrentTupel] := Text; {Fill the data string.}
      inc(CurrentTupel, 1)
    end
    end;
  ArrayResize(CurrentTupel);
  TupelNumber := CurrentTupel; {This is the maximum amount of tupels.}
  Close(DataFile)
end{TinstructionTable.FileRead}

procedure TInstructionTable.ArrayResize(Size: Word);
begin
  SetLength(DataString, Size);
  SetLength(DataTable.State, Size);
  SetLength(DataTable.Read, Size);
  SetLength(DataTable.Write, Size);
  SetLength(DataTable.Move, Size);
  SetLength(DataTable.Next, Size)
end{TInstructionTable.ArrayResize}

procedure TInstructionTable.TableFill();
var
  Position: Word;
  CurrentTupel: Word;
begin
  Position := 1;
  CurrentTupel := 0;
  while CurrentTupel <= TupelNumber do {Fill the record for each tupel.}
    begin
      while Position <= TupelLength do {Each tupel has a certain instruction at the same place, so the record is filled in a certain way.}
        begin
        case Position of
          1: DataTable.State[CurrentTupel] := DataString[CurrentTupel][Position];
        2: DataTable.Read[CurrentTupel]  := DataString[CurrentTupel][Position];
        3: DataTable.Write[CurrentTupel] := DataString[CurrentTupel][Position];
        4: DataTable.Move[CurrentTupel]  := DataString[CurrentTupel][Position];
        5: DataTable.Next[CurrentTupel]  := DataString[CurrentTupel][Position]
        end;
        inc(Position, 1)
      end;
    Position := 1;
    inc(CurrentTupel, 1)
  end
end{TInstructionTable.TableFill}

function TInstructionTable.GetWrite(CurrentState: Char; ReadData: Char): Char;
var
  Write: Char;
  EntryFound: Boolean;
  CurrentTupel: Integer;
begin
  EntryFound := false;
  CurrentTupel := 0;
  while not EntryFound do
  if (DataTable.State[CurrentTupel] = CurrentState) and (DataTable.Read[CurrentTupel] = ReadData) then {Tests, if the data pair exists in the record.}
    EntryFound := True
  else
    inc(CurrentTupel, 1);
  Write := DataTable.Write[CurrentTupel];
  GetWrite := Write
end{TInstructionTable.GetWrite}

function TInstructionTable.GetMove(CurrentState: Char; ReadData: Char): Char;
var
  Move: Char;
  EntryFound: Boolean;
  CurrentTupel: Integer;
begin
  EntryFound := false;
  CurrentTupel := 0;
  while not EntryFound do
  if (DataTable.State[CurrentTupel] = CurrentState) and (DataTable.Read[CurrentTupel] = ReadData) then {Tests, if the data pair exists in the record.}
    EntryFound := True
  else
    inc(CurrentTupel, 1);
  Move := DataTable.Move[CurrentTupel];
  GetMove := Move
end{TInstructionTable.GetMove}

function TInstructionTable.GetNext(CurrentState: Char; ReadData: Char): Char;
var
  Next: Char;
  EntryFound: Boolean;
  CurrentTupel: Integer;
begin
  EntryFound := false;
  CurrentTupel := 0;
  while not EntryFound do
  if (DataTable.State[CurrentTupel] = CurrentState) and (DataTable.Read[CurrentTupel] = ReadData) then {Tests, if the data pair exists in the record.}
    EntryFound := True
  else
    inc(CurrentTupel, 1);
  Next := DataTable.Next[CurrentTupel];
  GetNext := Next
end{TInstructionTable.GetNext}

constructor TInstructionTable.Create();
begin
  inherited;
  FileRead();
  TableFill()
end{TInstructionTable.Initialize}

function TInstructionTable.GetData(CurrentState: Char; ReadData: Char; DataType: Char): Char;
var
  Data: Char;
begin
  case DataType of {Used this way, so only one public function exists, instead of three.}
    'W': Data := GetWrite(CurrentState, ReadData);
  'M': Data := GetMove(CurrentState, ReadData);
  'N': Data := GetNext(CurrentState, ReadData)
  end;
  GetData := Data
end{TInstructionTable.GetData}

destructor TInstructionTable.FreeAndNil();
begin
  ArrayResize(0);
  inherited
end;

begin
end{TuringTable}


turingtable.txt
ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
/This is the table for the turing machine.
/Here you can define the instructions for the machine.
/Please use the given format.
/The start state is 'A'. 
/Use 'S' for staying, 'L' for moving the head leftwards and 'R' for moving the head rightwards.
/'H' is used to stop the machine.
/The head starts in the middle of the tape.
/If the array is expanded, it is filled with '0'.
/Lines are commented out when they begin with '/'.
/State Read Write Move Next

/Busy beavers taken from en.wikipedia.org

/2-state, 2-symbol busy beaver
/A01LB
/A11RB
/B01RA
/B11LH

/3-state, 2-symbol busy beaver
/A01LB
/A11RC
/B01RA
/B11LB
/C01RB
/C11SH

/4-state, 2-symbol busy beaver
A01LB
A11RB
B01RA
B10RC
C01LH
C11RD
D01LD
D10LA

/5-state, 2-symbol best contender busy beaver
/A01LB
/A11RC
/B01LC
/B11LB
/C01LD
/C10RE
/D01RA
/D11RD
/E01LH
/E10RA

/6-state, 2-symbol best contender busy beaver
/A01LB
/A11RE
/B01LC
/B11LF
/C01RD
/C10LB
/D01LE
/D10RC
/E01RA
/E10LD
/F01RH
/F11LC


memory.txt
ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
C:\Programming_Software\FreePascal\2.6.0\projects\Turing_Machine\memory\turing.exe 
Marked memory at $00075200 invalid
Wrong signature $D410291C instead of A7A141DB
  $0040F84B
  $0040F907
  $004154FD
  $004159ED
  $00401F3F  TMACHINE__FREEANDNIL,  line 203 of turing.pas
  $00402014  main,  line 217 of turing.pas
  $0040C7A1
Heap dump by heaptrc unit
714 memory blocks allocated : 14207/18256
706 memory blocks freed     : 14061/18080
8 unfreed memory blocks : 146
True heap size : 458752 (144 used in System startup)
True free heap : 457824
Should be : 457920
Call trace for block $000753E0 size 22
  $004018CF  TMACHINE__TAPERESIZE,  line 104 of turing.pas
  $00401E81  TMACHINE__RUN,  line 181 of turing.pas
  $00402000  main,  line 215 of turing.pas
  $0040C7A1
Marked memory at $00075380 invalid
Wrong signature $7C413530 instead of F25D645E
  $004106B7
  $0040F84B
  $0040F907
  $004154FD
  $004159ED
  $00401F3F  TMACHINE__FREEANDNIL,  line 203 of turing.pas
  $00402014  main,  line 217 of turing.pas
  $0040C7A1
Marked memory at $00075320 invalid
Wrong signature $65B2F7C9 instead of 4D5F691D
  $004106B7
  $0040F84B
  $0040F907
  $004154FD
  $004159ED
  $00401F3F  TMACHINE__FREEANDNIL,  line 203 of turing.pas
  $00402014  main,  line 217 of turing.pas
  $0040C7A1
Marked memory at $000752C0 invalid
Wrong signature $4FA6B0C2 instead of 07312F06
  $004106B7
  $0040F84B
  $0040F907
  $004154FD
  $004159ED
  $00401F3F  TMACHINE__FREEANDNIL,  line 203 of turing.pas
  $00402014  main,  line 217 of turing.pas
  $0040C7A1
Marked memory at $00075260 invalid
Wrong signature $5655723B instead of 6748E28D
  $004106B7
  $0040F84B
  $0040F907
  $004154FD
  $004159ED
  $00401F3F  TMACHINE__FREEANDNIL,  line 203 of turing.pas
  $00402014  main,  line 217 of turing.pas
  $0040C7A1
Marked memory at $00075200 invalid
Wrong signature $D410291C instead of A7A141DB
  $004106B7
  $0040F84B
  $0040F907
  $004154FD
  $004159ED
  $00401F3F  TMACHINE__FREEANDNIL,  line 203 of turing.pas
  $00402014  main,  line 217 of turing.pas
  $0040C7A1
Call trace for block $0007C3C8 size 32
  $00401C59  TMACHINE__CREATE,  line 141 of turing.pas
  $00401FD7  main,  line 213 of turing.pas
  $0040C7A1
  $00610068
  $00650072
  $005C0064
  $00690057
  $0064006E
Call trace for block $000751A0 size 24
  $00401FD7
  $0040C7A1
  $0040C7A1
haentschman
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 285
Erhaltene Danke: 33


DX10 Berlin Professional
BeitragVerfasst: So 02.09.12 19:26 
Hallo...

ohne jetzt tiefgründiger einzusteigen. Nenne deine Destruktoren nicht FreeAndNil sondern Destroy. Eventuell biegt der Compiler falsch ab wegen der gleichnamigen Objekt Procedur.
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 02.09.12 21:46 
Petroglyph, herzlich willkommen in diesem Forum! So sieht eine aufrichtige Neuanmeldung aus und nicht diese Trollheimsuchungen, die wir in letzter Zeit mehrmals hatten.

Hattest Du es schon mal mit dem Debuggen versucht? Davon las ich in Deinem Text nichts. Könntest Du evtl. auch mal das gesamte Projekt hier veröffentlichen ("hochladen"), wobei die compilierten Units und die Exe-Datei nicht unbedingt dazugehören?

Für diesen Beitrag haben gedankt: Petroglyph
Tankard
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Administrator
Beiträge: 217
Erhaltene Danke: 96



BeitragVerfasst: So 02.09.12 22:19 
du leitest von tobject ab. da heist der destructor destroy. benenne deinen destructor mal um in destroy, dann sollte es klappen. hab aber nur mal so grob drueber geschaut.

gruss
tankard

Für diesen Beitrag haben gedankt: Petroglyph
Petroglyph Threadstarter
Hält's aus hier
Beiträge: 7

Windows Vista, Ubuntu 12.03
Delphi 7 Personal, Edition Free Pascal, Lazarus, Lua(Scite)
BeitragVerfasst: So 02.09.12 22:45 
Schon einmal vielen Dank für die Hilfen,

ich habe den Rat von Tankard und haentschman befolgt und die Destruktoren in "Destroy" umbenannt. Leider stehen im Speicherbericht immer noch 8 nicht freigegebene Blöcke. Jetzt sind aber von ein paar mehr Informationen über die Aufrufe Unit "turingtable.pas" dabei. Das hängt aber glaube ich damit zusammen, dass ich das Programm vollständig neu kompilierte. Eine Frage habe ich aber dennoch: Als ich den Destruktor deklarierte, warnte mich der Compiler, dass "Destroy" eine versteckte Methode sei. Deshalb habe ich ihn mit dem Schlüsselwort "Override" überschrieben. War das so richtig?
Danke Delphi-Laie, ich bin schon etwas länger angemeldet, habe aber bisher nur gelesen(unter anderem auch diese "Vorstellungsthemen"). Ich habe vorher noch nicht mit FPCs Debugger gearbeitet und deshalb nur wenige Informationen bekommen. Was ich allerdings hearusfand ist, dass das Programm nicht mit dem Exitcode 00 beendet wird, sondern mit 01. Dieser steht nach der Dokumentation für "Invalid function number An invalid operating system call was attempted.". Allerdings weiß ich nicht, wie mir das weiterhilft.
Ich hänge diesmal auch die Quelltextdateien und Anweisungen an. Die Textdatei muss im gleichen Ordner, wie die Exe sein. Als Eingabe verwende ich zum Testen immer "y", "1" und "0"(für Ausgabeart, Startlänge und Startdaten).

Edit: Ich vergaß den Speicherbericht anzuhängen. Die Quelltextdateien sind ohne die "heaptrc"-Unit.
Einloggen, um Attachments anzusehen!
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: So 02.09.12 22:51 
Für ein vollständiges Projekt fehlen aber leider noch ein paar Dateien. Die Units sind ja oben schon als Quelltexte aufgeführt.

Wollte gerade mit dem Einladen des Projektes, Compilieren und weiteren glückshormonausstoßenden Freudentätigkeiten beginnen, doch so wird das leider nichts.

Edit: Das nehme ich zurück. Für ein Nicht-Formularprogramm reicht doch schon die Pascaldatei aus.


Zuletzt bearbeitet von Delphi-Laie am Mo 03.09.12 17:38, insgesamt 1-mal bearbeitet
Petroglyph Threadstarter
Hält's aus hier
Beiträge: 7

Windows Vista, Ubuntu 12.03
Delphi 7 Personal, Edition Free Pascal, Lazarus, Lua(Scite)
BeitragVerfasst: So 02.09.12 23:03 
Ich habe gerade den Pc heruntergefahren(schreibe auf dem Smartphone) und kann es deshalb leider nicht sofort liefern, aber was fehlt denn? Ausser dieser Dateien sind nur noch die .o, .exe und .ppu Datei/en in dem Ordner, was ja die compilierten Units bzw. die Exe sind, oder? Ich würde sie natürlich so schnell wie möglich nachliefern, was wahrscheinlich morgen Mittag wäre.
Tankard
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Administrator
Beiträge: 217
Erhaltene Danke: 96



BeitragVerfasst: Mo 03.09.12 06:40 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
{Implementation of the main program.}
begin
  Machine := TMachine.Create();
  try
    Machine.Run()
  finally
    Machine.FreeAndNil()
  end;
  ReadLn()
end.


einen destructor ruft man nie selber auf.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
{Implementation of the main program.}
begin
  Machine := TMachine.Create();
  try
    Machine.Run()
  finally
    Machine.Free
  end;
  ReadLn()
end.


Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt

Für diesen Beitrag haben gedankt: Petroglyph
Petroglyph Threadstarter
Hält's aus hier
Beiträge: 7

Windows Vista, Ubuntu 12.03
Delphi 7 Personal, Edition Free Pascal, Lazarus, Lua(Scite)
BeitragVerfasst: Mo 03.09.12 17:29 
user profile iconTankard hat folgendes geschrieben Zum zitierten Posting springen:
einen destructor ruft man nie selber auf.

Ich bedanke mich für den Hinweis, habe das jetzt korrigiert. Leider ergab auch das keine Verbesserung. Mir fiel inzwischen auf, dass wenn ich das Programm mit Speicherbericht laufenlasse, die letzte Zeile "The turing machine stopped. You can end the program by pressing enter." nicht angezeigt wird. Auch meine Eingabe zum Beenden des Programms durch "ReadLn()" scheint ignoriert zu werden, da ich nach der Ausgabe der Zustände sofort in die Befehlszeile der Konsole weitergeleitet werde.
Diesesmal hänge ich zwei Varianten sämtlicher im Programmordner enthaltenen Dateien an. Die erste ist die normale, während die zweite den Speicherbericht beinhaltet und die Unit "turing.pas" die "heaptrc"-Unit beinhaltet.

Edit: Grammatikfehler korrigiert.
Einloggen, um Attachments anzusehen!
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Mo 03.09.12 17:46 
Wie ich nunmehr mitbekam, reicht doch bei einem solchen Nichtformularprogramm eine zentrale Pascaldatei aus. Das kannte ich von Delphi so nicht: Dort muß man auch bei Konsolenprogrammen die dpr-Datei als zentrale benutzen.

Ich hülfe Dir gern weiter, doch ist mir schleierhaft, was ich eingeben muß, damit die Turingmaschine irgendetwas sinnvolles tut oder sich wenigstens nicht in einer Endlosschleife verfängt (das ist, wie einen beliebigen Binärcode ausführen zu wollen - die Wahrscheinlichkeit, daß das Programm überhaupt nur irgendwann endet, ist praktisch so gut wie null). Und ohne Minimalablaufsinn des Programmes ist jeder Hilfeversuch wahrscheinlich vergebens.


Zuletzt bearbeitet von Delphi-Laie am Mo 03.09.12 18:33, insgesamt 1-mal bearbeitet
Petroglyph Threadstarter
Hält's aus hier
Beiträge: 7

Windows Vista, Ubuntu 12.03
Delphi 7 Personal, Edition Free Pascal, Lazarus, Lua(Scite)
BeitragVerfasst: Mo 03.09.12 18:12 
Ich werde versuchen zu erklären, wie das Programm bedient werden soll. Eine Dokumentation schreibe ich auch noch, wenn das Programm ganz fertig ist. Allgemein kann ich zum weiteren Verständnis die Wikipediaartikel "Turingmaschine" und "Busy Beaver" empfehlen.
Der erste wichtige Teil ist die Datei "turingtable.txt". In ihr sind in Fünfertupeln die Anweisungen der Maschine gespeichert. Zeilen, die mit einem "/" beginnen sind auskommentiert. Es sollte auch nur ein Programm nicht auskommentiert sein, da das ansonsten zu Fehlern führt. Als Beispiel nehme ich mal die erste Zeile des 4-State Busy Beavers.
Diese lautet "A01LB". Das "A" steht für den Zustand, in dem sich die Maschine im Moment befindet. Das kann in diesem Beispiel ein Wert von "A" bis "D" sein. Die Maschine startet immer im Zustand "A".
Die "0"(muss nicht unbedingt eine Zahl sein) steht für das Zeichen, welches die Maschine im jetzigen Schritt gelesen hat. In Kombination mit dem Zustand erhält man so die weiteren Anweisungen der Maschine.
Die "1" gibt das Zeichen an, das auf das Feld, auf dem sich der Kopf gerade befindet, geschrieben wird. Das "L" bestimmt die Bewegungsrichtung des Kopfes, was entweder links, rechts oder gar nicht sein kann.
Das letzte Zeichen "B" gibt den Zustand an, in dem sich die Maschine im nächsten Arbeitsschritt befindet.
Wenn das Programm gestartet wird, fragt es erst einmal, ob eine ständige Ausgabe gewünscht ist. Das ist eingebaut, da diese Ausgabe das Programm stark verlangsamt und zum Beispiel den 5-State Busy Beaver viel zu lange dauern lässt.
Danach wird die Startlänge des Bandes, auf dem die Daten stehen abgefragt. Dort wähle ich meistens "1", da die Tests einfach nur möglich viele Einsen schreiben sollen. Wenn die Maschine aber zum Beispiel zwei Zahlen addieren soll, dann braucht man natürlich Startwerte, die am Anfang auf das Band geschrieben werden müssen.
Danach werden diese Startwerte abgefragt. Hier wähle ich meistens eine einzelne "0". Leider konnte ich noch nicht abfangen, dass die Eingabe möglicherweise nicht auf die Bandlänge passt.
Nach der Eingabe läuft die Maschine. Je nach Ausgabeart sieht man entweder alle Ergebnisse oder nur das Endergebnis. Übrigens sind die Ergebnisse im Vergleich zu den Ergebnissen auf Wikipedia gespiegelt, da ich den Kopf und nicht das Band bewege.
Petroglyph Threadstarter
Hält's aus hier
Beiträge: 7

Windows Vista, Ubuntu 12.03
Delphi 7 Personal, Edition Free Pascal, Lazarus, Lua(Scite)
BeitragVerfasst: So 14.10.12 14:44 
Ich habe gerade eben die Frage auf stackoverflow gepostet (Crosspost: stackoverflow.com/qu...al/12881958#12881958 ).
Dank der Hilfe dort fand ich heraus, dass meine dynamischen Arrays zu klein waren, und so Speicher korrumpiert wurde. Herausgefunden hat das der Helfer indem er den Quelltext mit der Option '-Cr' kompilierte. Die folgende Änderung in Linie 68 des Quelltextes von turingtable.pas hatte das Ergebnis, dass keine Speicherlecks mehr festgestellt wurden.
ausblenden Delphi-Quelltext
1:
2:
  ArrayResize(CurrentTupel); {Alter Quelltext, Arrays sind 1 Feld zu klein.}
  ArrayResize(CurrentTupel + 1); {Neuer Quelltext, produziert keine Speicherlecks mehr.}

Obwohl ich hier nicht die Antwort erhielt, möchte ich mich doch für die Hilfe hier herzlich bedanken, da ich auf ein paar andere Fehler in meinem Quelltext hingewiesen wurde. Ich vermute auch, dass meine Beschreibung des Programms nicht gerade die Beste war, was natürlich nicht bei der Lösung des Problems half.
Einen schönen Sonntag noch,
Petroglyph
Fiete
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 617
Erhaltene Danke: 364

W7
Delphi 6 pro
BeitragVerfasst: Mo 15.10.12 12:53 
Moin Petroglyph,
da Du dich für die Turingmaschine interessierst, hier zwei Links die Dich weiterbringen könnten:
Simulator für eine TM
www.entwickler-ecke....light=turingmaschine
Bibersuchprogramm
www.entwickler-ecke....ighlight=busy+beaver
Gruß Fiete

_________________
Fietes Gesetz: use your brain (THINK)