Delphi를 한 라이너로 쓸 수 있습니다.

18255 단어 델파이

Delphi의 원라이너란?



기세로 「원 라이너 자랑 대회」란 Advent Calendar를 만든 것은 좋은 것의, 원래 Delphi에서는 원 라이너다운 원 라이너 쓸 수 없다! ? 라고...

제 안에서의 「원라이너다운 원라이너」는 단순히 1행으로 실행할 수 있다는 뜻은 아니고 콘솔로부터 기동하고 싶다고 하는 생각이 있어, 그러면 컴파일 언어인 Object Pascal 는 그것이 할 수 없는 것입니다.

그래서 먼저 콘솔에서 컴파일러를 호출하는 프로그램을 만들었습니다.
그것이 dcce입니다.

dcce



소스 코드는 이렇게!
program dcce;

{$APPTYPE CONSOLE}
{$RTTI EXPLICIT METHODS([]) FIELDS([]) PROPERTIES([])}
{$WEAKLINKRTTI ON}

uses
  System.SysUtils, System.IOUtils, Winapi.Windows;

function GetReg(const iKey: HKEY; const iAddress, iValue: String): String;
begin
  var hReg: HKEY := 0;
  var Ret := RegOpenKeyEx(iKey, PChar(iAddress), 0, KEY_QUERY_VALUE, hReg);
  try
    if Ret = ERROR_SUCCESS then
    begin
      SetLength(Result, $ff);
      var RegType: DWORD := REG_SZ;
      var VarSize: DWORD := Length(Result);

      Ret :=
        RegQueryValueEx(
          hReg,
          PChar(iValue),
          nil,
          @RegType,
          PByte(PChar(Result)),
          @VarSize
        );

      if Ret = ERROR_SUCCESS then
      begin
        SetLength(Result, VarSize div SizeOf(Char));
        Result := Result.Trim;
      end
      else
        Result := '';
    end;
  finally
    RegCloseKey(hReg);
  end;
end;

procedure Exec(const iCmd: String; const iNeedOutput: Boolean);
var
  SI: TStartUpInfo;
  PI: TProcessInformation;
begin
  ZeroMemory(@SI, SizeOf(SI));
  with SI do
  begin
    cb := SizeOf(SI);

    if not iNeedOutput then
      dwFlags := STARTF_USESTDHANDLES;
  end;

  if CreateProcess(nil, PChar(iCmd), nil, nil, True, 0, nil, nil, SI, PI) then
    with PI do
      try
        while WaitForSingleObject(PI.hProcess, 100) = WAIT_TIMEOUT do
          ;
      finally
        CloseHandle(hProcess);
        CloseHandle(hThread);
      end;
end;

begin
  var DprPath := TPath.ChangeExtension(TPath.GetTempFileName, '.dpr');
  var ExePath := TPath.ChangeExtension(DprPath, '.exe');
  try
    var Writer := TFile.CreateText(DprPath);
    try
      Writer.Write('begin ');

      for var i := 1 to ParamCount do
        Writer.Write(ParamStr(i) + ' ');

      Writer.Write(' end.');
    finally
      Writer.DisposeOf;
    end;

    Exec(
      TPath.Combine(
        GetReg(HKEY_CURRENT_USER, 'Software\Embarcadero\BDS\20.0', 'RootDir'),
        'bin\dcc32.exe -Q -CC '
      ) + DprPath,
      False);

    Exec(ExePath, True);
  finally
    if TFile.Exists(DprPath) then
      TFile.Delete(DprPath);

    if TFile.Exists(ExePath) then
      TFile.Delete(ExePath);
  end;
end.

하는 일은 간단하고,
  • 명령줄 인수를 임시 파일에 저장합니다. 그 때 begin end.에 끼워 넣는다
  • 레지스트리에서 Delphi 10.3 Rio Win32 컴파일러 dcc32.exe의 경로 얻기
  • dcc32에 1로 저장된 파일을 전달합니다.
  • 완성 된 exe 실행
  • 임시 파일과 exe 파일 삭제

  • 그리고 이것만입니다.

    덧붙여서 dcc32 에 건네주고 있는 인수의 -Q 는 침묵 컴파일 (불필요한 정보가 출력되지 않게 된다), -CC 는 컴파일 대상이 콘솔용,이라는 것을 나타냅니다.
    -CC 를 지정하지 않으면 GUI 타겟이 되어 기동에 실패합니다.

    실행하면 이런 느낌입니다.
    역시 Delphi! 마치 인터프리터 같은 속도로 움직인다!


    원라이너 FizzBuzz



    라고 dcce 따위 만들고 있었기 때문에 당초 예정하고 있던 원라인 BrainF*ck 가 완성되지 않았습니다…

    그렇다면 원라인 FizzBuzz에서 차를 탁하게 ...
    그것이 이것입니다.
    for var i := 1 to 100 do Writeln((function(const M: array of String): String begin Result := M[Ord(i mod 3 = 0) or Ord(i mod 5 = 0) * 2] end)([(function(N: Integer): String begin Str(N, Result) end)(i), 'Fizz','Buzz','FizzBuzz']))
    

    위의 코드를 읽기 쉽게 한 것이 이것입니다.
    for var i := 1 to 100 do
      Writeln(
        (
          function(const S: array of String): String
          begin
            Result := S[Ord(i mod 3 = 0) or Ord(i mod 5 = 0) * 2]
          end
        )([
          (
            function(N: Integer): String
            begin
              Str(N, Result)
            end
          )(i),
          'Fizz',
          'Buzz',
          'FizzBuzz'
        ])
      )
    

    Object Pascal 에서의 원라이너는 기본적으로 세미콜론리스 와 같을까 생각하고 있습니다.
    그렇다고 하는 것으로, 익명 함수를 꽉 사용하고 있습니다.
    물론 세미콜론을 사용할 수 없기 때문에 uses 도 없음. System 유닛의 함수만으로 만듭니다.
    Str 절차 라든지 오랜만에 사용했다.

    다만 Delphi 10.3 Rio 에서는 Pascal 전통의 var 블록 없이 인라인 변수 선언과 유형 추론을 사용할 수 있습니다. 때문에 세미콜론리스가 이전보다는 간편하게 실현되고 있습니다.

    수행한 결과




    요약



    기세로 Advent Calendar 만들면 안돼!



    만약 이 기사에서 Delphi가 신경이 쓰이는 분은, 상용판과 같은 기능을 사용할 수 있는 완전 무료의 델파이 10.3 리오 커뮤니티 에디션 를 사용해 보세요!
    무료로 Windows, macOS, Android, iOS를 개발할 수 있어요!

    좋은 웹페이지 즐겨찾기