Mój cel:
Wychodząc od zbiorów znaków, chcę dojść do składowych języka programowania np. identyfikatorów zmiennych i typów, dalej składni języka itd., w końcu interpretera. Ale tu na forum chodzi mi tylko o napisanie maksymalnie poprawnie programu, który widać, żeby mieć go na wzór. Potem wątek zakończę. Mam zamiar w Delphi napisać interpreter starego języka programowania na Atari, z czasów komputerów 8-bitowych, języka o nazwie Action! Ale przede wszyskim poćwiczyć Delphi i temu to głównie służy.
Moje doświadczenia w C#
Przykład prostego interpretera własnego języka – podstawy
Jak to się zaczęło:
Wątek został rozpoczęty na moim Mikroblogu. To dwa posty oznaczone hashtagiem #universum Wątek się rozrósł i dlatego przenoszę go na forum. Jak dotąd był to dialog z @furious programming za co jestem mu wdzięczny, za jego zaangażowanie w, że tak powiem "odnowę" mojej osoby, jako programisty. Na chwilę obecną jest to poniższy program, gdzie doszedłem do słówka:
inherited
i nie bardzo wiem, gdzie je tu "przypiąć", co nie znaczy, że nie wiem do czego służy np. do wywołania metody odziedziczonej.
{
Zmiany:
Zakresy cyfr i liter ustalane przy pomocy zbiorów
Aplikacja konsolowa
Log zamiast ShowMessage
Teksty jako stałe np. 'cyfra' jako SDigit
Parametry String jako const
_className zamienione na FClassName (pole prywatne TAlphanum)
Nazwy typów z prefiksem T oraz dalej duża litera, pozostałe małe
Nazwy typów String, Char, Integer z dużej litery
Wprowadzone $REGION - y
Parametry z prefiksem A podobnie do nazw typów
nazwy zmiennych, wprawdzie z małej litery, ale pełnym wyrazem
zwalnianie zmiennych przez Free
Blok chroniony try..except dla zminnej niezainicjowanej 'alien'
}
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
Classes;
const
SUnknown = '<Alien>';
SDigit = '<Digit>';
SAlpha = '<Alpha>';
SAlphanum = '<Alphanum>';
type
TDigit = class;
TAlpha = class;
TAlphanum = class abstract
private
FClassName: String;
public
function WhatIs(AChar: Char; ALog: TStrings): String; overload; virtual;
function WhatIs(ATDigit: TDigit; ALog: TStrings): String; overload; virtual;
function WhatIs(ATAlpha: TAlpha; ALog: TStrings): String; overload; virtual;
constructor Create(const AClassName: String);
end;
TDigit = class(TAlphanum)
public
function WhatIs(AChar: Char; ALog: TStrings): String; override;
function WhatIs(ATDigit: TDigit; ALog: TStrings): String; override;
end;
TAlpha = class(TAlphanum)
public
function WhatIs(AChar: Char; ALog: TStrings): String; override;
function WhatIs(ATAlpha: TAlpha; ALog: TStrings): String; override;
end;
{$REGION 'TAlphanum'}
constructor TAlphanum.Create(const AClassName: String);
begin
FClassName := AClassName
end;
function TAlphanum.WhatIs(AChar: Char; ALog: TStrings): String;
var
digit: TDigit;
alpha: TAlpha;
begin
ALog.Add('Have been to #1');
digit := TDigit.Create(SDigit);
alpha := TAlpha.Create(SAlpha);
if digit.WhatIs(AChar, ALog) <> SUnknown then
Result := digit.WhatIs(AChar, ALog)
else
if alpha.WhatIs(AChar, ALog) <> SUnknown then
Result := alpha.WhatIs(AChar, ALog)
else
Result := SUnknown;
digit.Free;
alpha.Free;
end;
function TAlphanum.WhatIs(ATDigit: TDigit; ALog: TStrings): String;
var
digit: TDigit;
begin
digit := TDigit.Create(SDigit);
Result := digit.WhatIs(ATDigit, ALog);
digit.Free;
end;
function TAlphanum.WhatIs(ATAlpha: TAlpha; ALog: TStrings): String;
var
alpha: TAlpha;
begin
alpha := TAlpha.Create(SAlpha);
Result := alpha.WhatIs(ATAlpha, ALog);
alpha.Free;
end;
{$ENDREGION}
{$REGION 'TDigit'}
function TDigit.WhatIs(AChar: Char; ALog: TStrings): String;
begin
ALog.Add('Have been to #2');
if AChar in ['0'..'9'] then
Result := FClassName
else
Result := SUnknown;
end;
function TDigit.WhatIs(ATDigit: TDigit; ALog: TStrings): String;
begin
ALog.Add('Have been to #3');
Result := ATDigit.FClassName;
end;
{$ENDREGION}
{$REGION 'TAlpha'}
function TAlpha.WhatIs(AChar: Char; ALog: TStrings): String;
begin
ALog.Add('Have been to #4');
if AChar in ['A'..'Z'] then
Result := FClassName
else
Result := SUnknown;
end;
function TAlpha.WhatIs(ATAlpha: TAlpha; ALog: TStrings): String;
begin
ALog.Add('Have been to #5');
Result := ATAlpha.FClassName;
end;
{$ENDREGION}
var
log: TStringList;
alphanum: TAlphanum;
digit: TDigit;
alpha: TAlpha;
alien: Char;
i: Integer;
begin
log := TStringList.Create;
alphanum := TAlphanum .Create(SAlphanum);
digit := TDigit.Create(SDigit);
alpha := TAlpha.Create(SAlpha);
log.Add('Character ''7'' is of type ' + alphanum.WhatIs('7', log));
log.Add('Character ''A'' is of type ' + alphanum.WhatIs('A', log));
log.Add('Character ''$'' is of type ' + alphanum.WhatIs('$', log));
log.Add('Variable ''digit'' is of type ' + alphanum.WhatIs(digit, log));
log.Add('Variable ''alpha'' is of type ' + alphanum.WhatIs(alpha, log));
try
{[Pascal Warning] W1036 Variable 'alien' might not have been initialized}
log.Add('Variable ''alien'' is of type ' + alphanum.WhatIs(alien, log));
except
log.Add('Error: Variable ''alien'' not initialized');
end;
for i := 0 to log.Count - 1 do
WriteLn(log[i]);
WriteLn;
Write('Press key Enter');
ReadLn;
log.Free;
alphanum.Free;
digit.Free;
alpha.Free;
end.
Co widać na konsoli:
{
Have been to #1
Have been to #2
Have been to #2
Character '7' is of type <Digit>
Have been to #1
Have been to #2
Have been to #4
Have been to #4
Character 'A' is of type <Alpha>
Have been to #1
Have been to #2
Have been to #4
Character '$' is of type <Alien>
Have been to #3
Variable 'digit' is of type <Digit>
Have been to #5
Variable 'alpha' is of type <Alpha>
Have been to #1
Have been to #2
Have been to #4
Variable 'alien' is of type <Alien>
Press key Enter
}
Artur Protasewicz