Changeset 18 for trunk/UBrainFuck.pas


Ignore:
Timestamp:
Feb 11, 2012, 9:32:25 PM (12 years ago)
Author:
chronos
Message:
  • Modified: Optimalized execution of BrainFuck commands using array of methods instead of case statement. This can scale better for future additional commands.
  • Added: Interpretter form show speed in steps per second.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UBrainFuck.pas

    r17 r18  
    3939  end;
    4040
     41  TBrainFuckCommand = (cmNone, cmInc, cmDec, cmPointerInc, cmPointerDec,
     42    cmOutput, cmInput, cmLoopStart, cmLoopEnd);
     43
     44  TCommandHandler = procedure of object;
     45
    4146  { TBrainFuckInterpretter }
    4247
     
    4954    FThread: TBrainFuckInterpretterThread;
    5055    FStepCount: Integer;
     56    FCommandTable: array[TBrainFuckCommand] of TCommandHandler;
    5157    function GetMemorySize: Integer;
    52     function GetSource: string;
    5358    procedure SetMemorySize(AValue: Integer);
    5459    procedure SetSource(AValue: string);
    5560    procedure SetState(AValue: TRunState);
    56     procedure Write(Value: Byte);
    57     function Read: Byte;
    5861    procedure SetThread(State: Boolean);
    5962    procedure PrepareJumpTable;
    60     procedure RemoveBlankCharacters;
     63    procedure CommandInc;
     64    procedure CommandDec;
     65    procedure CommandPointerInc;
     66    procedure CommandPointerDec;
     67    procedure CommandInput;
     68    procedure CommandOutput;
     69    procedure CommandLoopStart;
     70    procedure CommandLoopEnd;
    6171  public
    62     FSource: array of Char;
     72    FSource: array of TBrainFuckCommand;
    6373    SourceJump: array of Integer;
    6474    SourcePosition: Integer;
     
    8090    property OnChangeState: TNotifyEvent read FOnChangeState write FOnChangeState;
    8191    property StepCount: Integer read FStepCount;
    82     property Source: string read GetSource write SetSource;
     92    property Source: string write SetSource;
    8393    property MemorySize: Integer read GetMemorySize write SetMemorySize;
    8494    property CellSize: Integer read FCellSize write FCellSize;
     
    113123{ TBrainFuckInterpretter }
    114124
    115 procedure TBrainFuckInterpretter.Write(Value: Byte);
    116 begin
    117   if OutputPosition > Length(Output) then
    118     SetLength(Output, Length(Output) + 1 + Length(Output) div 4);
    119   Output[OutputPosition] := Char(Value);
    120   Inc(OutputPosition);
    121 end;
    122 
    123125procedure TBrainFuckInterpretter.SetState(AValue: TRunState);
    124126begin
     
    128130end;
    129131
    130 function TBrainFuckInterpretter.GetSource: string;
    131 var
    132   I: Integer;
    133 begin
    134   SetLength(Result, Length(FSource));
    135   //Move(Pointer(Result)^, Pointer(FSource)^, Length(Result));
    136   for I := 0 to Length(FSource) - 1 do
    137     Result[I + 1] := FSource[I];
    138 end;
    139 
    140132function TBrainFuckInterpretter.GetMemorySize: Integer;
    141133begin
     
    151143var
    152144  I: Integer;
     145  Pos: Integer;
    153146begin
    154147  SetLength(FSource, Length(AValue));
    155   //Move(Pointer(AValue)^, Pointer(FSource)^, Length(AValue));
    156   for I := 0 to Length(FSource) - 1 do
    157     FSource[I] := AValue[I + 1];
    158 end;
    159 
    160 function TBrainFuckInterpretter.Read: Byte;
    161 begin
    162   while (InputPosition > Length(Input)) and (FState <> rsStopped) do begin
    163     Sleep(1);
    164   end;
    165   if InputPosition <= Length(Input) then begin
    166     Result := Ord(Input[InputPosition]);
    167     Inc(InputPosition);
    168   end else Result := 0;
     148  Pos := 0;
     149  for I := 1 to Length(AValue) do begin
     150    case AValue[I] of
     151      '+': FSource[Pos] := cmInc;
     152      '-': FSource[Pos] := cmDec;
     153      '>': FSource[Pos] := cmPointerInc;
     154      '<': FSource[Pos] := cmPointerDec;
     155      ',': FSource[Pos] := cmInput;
     156      '.': FSource[Pos] := cmOutput;
     157      '[': FSource[Pos] := cmLoopStart;
     158      ']': FSource[Pos] := cmLoopEnd;
     159      else Dec(Pos);
     160    end;
     161    Inc(Pos);
     162  end;
     163  SetLength(FSource, Pos);
    169164end;
    170165
     
    186181var
    187182  Loop: array of Integer;
    188   LoopCurrent: Integer;
    189183  I: Integer;
    190184begin
     
    196190  for I := 0 to Length(FSource) - 1 do begin
    197191    case FSource[I] of
    198       '[': begin
     192      cmLoopStart: begin
    199193        SetLength(Loop, Length(Loop) + 1);
    200194        Loop[High(Loop)] := I;
    201195      end;
    202       ']': begin
     196      cmLoopEnd: begin
    203197        if SourceJump[I] > 0 then raise Exception.Create(SJumpTableColision);
    204198        SourceJump[I] := Loop[High(Loop)];
     
    212206end;
    213207
    214 procedure TBrainFuckInterpretter.RemoveBlankCharacters;
    215 var
    216   I: Integer;
    217   LastChar: Integer;
    218 begin
    219   LastChar := 0;
    220   for I := 0 to Length(FSource) - 1 do
    221     if FSource[I] in ['+','-','>','<','.',',','[',']'] then begin
    222       FSource[LastChar] := FSource[I];
    223       Inc(LastChar);
    224     end;
    225   SetLength(FSource, LastChar);
     208procedure TBrainFuckInterpretter.CommandInc;
     209begin
     210  Memory[MemoryPosition] := ((Memory[MemoryPosition] + 1) mod CellSize);
     211end;
     212
     213procedure TBrainFuckInterpretter.CommandDec;
     214begin
     215  Memory[MemoryPosition] := ((Memory[MemoryPosition] - 1) mod CellSize);
     216end;
     217
     218procedure TBrainFuckInterpretter.CommandPointerInc;
     219begin
     220  if MemoryPosition < MemorySize then Inc(MemoryPosition)
     221    else raise Exception.Create(SProgramUpperLimit);
     222end;
     223
     224procedure TBrainFuckInterpretter.CommandPointerDec;
     225begin
     226  if MemoryPosition > 0 then Dec(MemoryPosition)
     227    else raise Exception.Create(SProgramLowerLimit);
     228end;
     229
     230procedure TBrainFuckInterpretter.CommandInput;
     231begin
     232  while (InputPosition > Length(Input)) and (FState <> rsStopped) do begin
     233    Sleep(1);
     234  end;
     235  if InputPosition <= Length(Input) then begin
     236    Memory[MemoryPosition] := Ord(Input[InputPosition]);
     237    Inc(InputPosition);
     238  end;
     239end;
     240
     241procedure TBrainFuckInterpretter.CommandOutput;
     242begin
     243  if OutputPosition > Length(Output) then
     244    SetLength(Output, Length(Output) + 1 + Length(Output) div 4);
     245  Output[OutputPosition] := Char(Memory[MemoryPosition]);
     246  Inc(OutputPosition);
     247end;
     248
     249procedure TBrainFuckInterpretter.CommandLoopStart;
     250begin
     251  if Memory[MemoryPosition] = 0 then
     252    SourcePosition := SourceJump[SourcePosition];
     253end;
     254
     255procedure TBrainFuckInterpretter.CommandLoopEnd;
     256begin
     257  if Memory[MemoryPosition] > 0 then
     258    SourcePosition := SourceJump[SourcePosition] - 1;
    226259end;
    227260
     
    230263  I: Integer;
    231264begin
    232   RemoveBlankCharacters;
    233265  PrepareJumpTable;
    234266  SourcePosition := 0;
     
    244276
    245277procedure TBrainFuckInterpretter.SingleStep;
    246 var
    247   CodeText: string;
    248   C: Integer;
    249   NewPos: Integer;
    250 begin
    251   case FSource[SourcePosition] of
    252     '>': if MemoryPosition < MemorySize then Inc(MemoryPosition)
    253       else raise Exception.Create(SProgramUpperLimit);
    254     '<': if MemoryPosition > 0 then Dec(MemoryPosition)
    255       else raise Exception.Create(SProgramLowerLimit);
    256     '+': Memory[MemoryPosition] := ((Memory[MemoryPosition] + 1) mod CellSize);
    257     '-': Memory[MemoryPosition] := ((Memory[MemoryPosition] - 1) mod CellSize);
    258     '.': Write(Memory[MemoryPosition]);
    259     ',': Memory[MemoryPosition] := Read;
    260     '[': begin
    261       if Memory[MemoryPosition] = 0 then begin
    262         SourcePosition := SourceJump[SourcePosition];
    263         (*C := 1;
    264         Inc(SourcePosition);
    265         while C > 0 do begin
    266           case ReadCode of
    267             '[': Inc(C);
    268             ']': Dec(C);
    269           end;
    270           Inc(SourcePosition);
    271         end;
    272         Dec(SourcePosition);*)
    273         //if NewPos <> SourcePosition then raise Exception.Create('Wrong pos: ' + IntToStr(SourcePosition) + ' ' + IntToStr(NewPos));
    274       end;
    275     end;
    276     ']': begin
    277       if Memory[MemoryPosition] > 0 then begin
    278         SourcePosition := SourceJump[SourcePosition] - 1;
    279         (*C := 1;
    280         Dec(SourcePosition);
    281         while C > 0 do begin
    282           case ReadCode of
    283             ']': Inc(C);
    284             '[': Dec(C);
    285           end;
    286           Dec(SourcePosition);
    287         end;
    288         if NewPos <> SourcePosition then raise Exception.Create('Wrong pos: ' + IntToStr(SourcePosition) + ' ' + IntToStr(NewPos));
    289         *)
    290       end;
    291     end;
    292   end;
     278begin
     279  FCommandTable[FSource[SourcePosition]];
    293280  Inc(SourcePosition);
    294281  Inc(FStepCount);
     
    317304  MemorySize := 30000;
    318305  CellSize := 256;
     306  FCommandTable[cmInc] := CommandInc;
     307  FCommandTable[cmDec] := CommandDec;
     308  FCommandTable[cmPointerInc] := CommandPointerInc;
     309  FCommandTable[cmPointerDec] := CommandPointerDec;
     310  FCommandTable[cmOutput] := CommandOutput;
     311  FCommandTable[cmInput] := CommandInput;
     312  FCommandTable[cmLoopStart] := CommandLoopStart;
     313  FCommandTable[cmLoopEnd] := CommandLoopEnd;
    319314end;
    320315
Note: See TracChangeset for help on using the changeset viewer.