2014-05-14 3 views
3

명령 줄 인터페이스와 대화 형 모드가 모두있는 프로그램을 작성하고 있습니다. CLI 모드에서는 하나의 명령을 실행하고 결과를 인쇄 한 후 종료합니다. 대화식 모드에서는 GNU readline을 사용하여 명령을 반복적으로 읽고 실행하고 결과를 인쇄합니다 (REPL의 정신으로).haskell - 명령 줄 및 REPL 명령과 옵션을 구문 분석

명령 및 해당 매개 변수의 구문은 명령 줄 또는 frmo stdin에 관계없이과 거의 동일하게 입니다. 명령 줄 및 대화 형 모드 입력을 모두 구문 분석하기위한 단일 프레임 워크를 사용하여 코드 재사용을 극대화하고 싶습니다.

<command> [{<command arg>|<GLOBAL OPTION>|<LOCAL OPTION> ...}] 
: 대화 형 모드에서

program-name {[GLOBAL OPTION] ...} <command> [{<command arg>|<GLOBAL OPTION>|<LOCAL OPTION> ...}] 
  • : 쉘에서

    • :

      내 제안 구문은 (대괄호가 반복 교정기, 선택적인 부분을 나타낸다)으로는 다음이다

      Loc al 옵션은 하나의 특정 명령에 대해서만 유효합니다 (다른 명령은 하나의 옵션에 다른 의미를 할당 할 수 있음).

      내 문제는 CL과 대화 형 인터페이스간에 약간의 차이가 있다는 것입니다. 일부 글로벌 옵션은 --help, --version 또는 --config-file과 같은 명령 행에서만 유효합니다. 명백히 대화식 모드에서 매우 중요한 'quit'명령도 있지만 CL에서 사용하는 것은 의미가 없습니다.

      이 문제를 해결하기 위해 명령 행 구문 분석 라이브러리에 대한 웹 및 해킹을 검색했습니다. 내가 찾은 가장 흥미로운 것들은 cmdlib와 optparse-applicative이다. 그러나 저는 Haskell에 아주 익숙하며 라이브러리 문서에서 예제 코드를 복사하고 수정하여 작동하는 프로그램을 만들 수는 있지만 라이브러리의 메커니즘을 이해하지 못하여 문제를 해결할 수 없었습니다.

      다음 질문을 염두에 두어주십시오 :
      CL 및 REPL 인터페이스에 공통적 인 명령 및 옵션에 대한 기본 파서를 작성한 다음 기본 파서를 새 명령 및 옵션으로 확장 할 수 있습니까?
      잘못된 입력이나 '--help'가 사용 된 경우이 라이브러리가 내 프로그램을 종료하지 못하게하려면 어떻게해야합니까?
      프로그램에 완전한 i18n 지원을 추가 할 계획입니다. 따라서 모든 메시지를 번역해야하기 때문에 선택한 메시지가 인쇄되지 않도록하고 싶습니다. 이것을 달성하는 방법?

      그래서 여기에서 어디로 가야할지 힌트를주세요. cmdlib 또는 optparse-applicative (또는 다른 라이브러리)가 내가 원하는 것을 지원합니까? 아니면 손으로 만든 파서로 되돌려 야합니까?

  • +0

    기본 명령 줄 구문 분석 도구는 http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-Console-GetOpt.html입니다. 귀하의 옵션이 목록으로 주어지면, 공통 명령에 대한 목록, REPL 전용에 대한 목록 및 CL 전용 목록 등 세 가지 목록을 가질 수 있습니다. 'GetOpts'는 충돌하지 않으며, 오류 메시지를 반환합니다. 좋은 라이브러리가 있어야한다고 가정합니다. 인쇄 작업은 명령 행 구문 분석과 아무 관련이 없기 때문에 인쇄 작업도 수행하지 않습니다. – user2407038

    +0

    명령 줄 옵션을 구문 분석하기위한 기존 라이브러리에 대한 리뷰가 있습니다. http://www.haskell.org/haskellwiki/Command_line_option_parsers에서 확인하십시오. – fizruk

    답변

    2

    내 라이브러리 http://hackage.haskell.org/package/options을 사용하여이 작업을 수행 할 수 있다고 생각합니다. 부속 명령 기능은 찾고있는 명령 플래그 구문 분석 작동과 정확히 일치합니다.

    두 개의 분리 된 옵션 세트 사이에서 부속 명령을 공유하는 것은 약간 까다 롭지 만 도우미 typeclass가이를 수행 할 수 있어야합니다.거친 샘플 코드 :

    -- A type for options shared between CLI and interactive modes. 
    data CommonOptions = CommonOptions 
        { optSomeOption :: Bool 
        } 
    instance Options CommonOptions where ... 
    
    -- A type for options only available in CLI mode (such as --version or --config-file) 
    data CliOptions = CliOptions 
        { common :: CommonOptions 
        , version :: Bool 
        , configFile :: String 
        } 
    instance Options CliOptions where ... 
    
    -- if a command takes only global options, it can use this subcommand option type. 
    data NoOptions = NoOptions 
    
    instance Options NoOptions where 
        defineOptions = pure NoOptions 
    
    -- typeclass to let commands available in both modes access common options 
    class HasCommonOptions a where 
        getCommonOptions :: a -> CommonOptions 
    instance HasCommonOptions CommonOptions where 
        getCommonOptions = id 
    instance HasCommonOptions CliOptions where 
        getCommonOptions = common 
    
    commonCommands :: HasCommonOptions a => [Subcommand a (IO())] 
    commonCommands = [... {- your commands here -} ...] 
    
    cliCommands :: HasCommonOptions a => [Subcommand a (IO())] 
    cliCommands = commonCommands ++ [cmdRepl] 
    
    interactiveCommands :: HasCommonOptions a => [Subcommand a (IO())] 
    interactiveCommands = commonCommands ++ [cmdQuit] 
    
    cmdRepl :: HasCommonOptions a => Subcommand a (IO()) 
    cmdRepl = subcommand "repl" $ \opts NoOptions -> do 
        {- run your interactive REPL here -} 
    
    cmdQuit :: Subcommand a (IO()) 
    cmdQuit = subcommand "quit" (\_ NoOptions -> exitSuccess) 
    

    나는 당신이 REPL 프롬프트에서 입력 문자열을 분할 한 후 parseSubcommand로 파서를 호출 할 수 있습니다 있도록 runSubcommand 같은 도우미 기능을 충분히 전문화되지 않을 것이다 생각한다. 문서에는 사용자가 도움말을 요청했는지 확인하는 것을 포함하여 구문 분석 된 옵션을 검사하는 방법에 대한 예제가 있습니다.

    옵션 파서 자체는 출력물을 인쇄하지 않지만 기본 형식 파서로 생성 된 오류 메시지를 국제화하는 것은 어려울 수 있습니다. 도움이 될 수있는 라이브러리가 변경되면 알려 주시기 바랍니다.

    관련 문제