If it's sufficiently simple (even with optional arguments), something based on TStringList actually works decently. Here's a simple example to get you started:
type
TCommandRec = record
Command: string;
Proc: array(AArgs: TStringList);
end;
const
Commands: array(0..4) of TCommandRec = (
(Command: 'New'; Proc: DoNew),
(Command: 'Customer'; Proc: DoCustomer),
(Command: 'Run'; Proc: DoRun),
(Command: 'Scr'; Proc: DoScr),
(Command: 'Find'; Proc: DoFind));
procedure RunScript(const AFileName: string);
var
Script, Args: TStringList;
i, j: Integer;
begin
Script := TStringList.Create;
try
Script.LoadFromFile(AFileName);
Args := TStringList.Create;
try
Args.Delimiter := ' ';
for i := 0 to Script.Count - 1 do begin
Args.DelimitedText := Script[i];
for j := Low(Commands) to High(Commands) do
if SameText(Args[0], Commands[j].Command) then begin
Commands[j].Proc(Args);
Break;
end;
end;
finally
Args.Free;
end;
finally
Script.Free;
end;
end;
procedure DoRun(AArgs: TStringList);
begin
if SameText(AArgs[1], 'End-of-day') then
RunEndOfDayProcess
else if SameText(AArgs[1], 'Hourly') then
RunHourlyProcess
else
raise EInvalidScript.Create;
end;
procedure DoFind(AArgs: TStringList);
var
FindType: string;
begin
if (AArgs.Count <> 5) or not SameText(AArgs[2], 'by') then
raise EInvalidScript.Create;
if SameText(AArgs[1], 'Cust') then begin
if SameText(AArgs[3], 'Name') then
FindCustomer(AArgs[4], '')
else if SameText(AArgs[3], 'LastName') then
FindCustomer('', AArgs[4])
end
else if SameText(AArgs[1], 'Contact') then begin
...
end
else
raise EInvalidScript.Create;
end;
If you have multiple optional arguments (e.g., FIND CUST BY NAME John AND LASTNAME Smith
) then, rather than hardcoding the stringlist offsets like I've done above, delete each argument from the stringlist as you process it (or add it to your query). That way, when it's empty you know you're done with the line, and you only need to look at AArgs[0]
to see if you recognize the next bit.