4

이 질문은 이전에 제기되었지만 답변 중 어느 것도 boost- 스타일 일반 프로그래밍의 대안을 제공하지 않는 것으로 보입니다.시퀀스 컨테이너로 명령 줄 옵션을 구문 분석 하시겠습니까?

많은 사람들처럼 boost : program_options를 사용하여 명령 줄 옵션을 구문 분석합니다. 현재 진행중인 프로젝트는 순서가 바뀌지 않는 연산자 (예 : )를 사용하여 데이터 (예 : 이미지)를 조작하는 프로그램입니다.

추가 3 다음 곱하기 2
$ manipulate -in someimage.tif -a 3 -m 2

는 일반적으로 곱하기 2로

과 동일하지 않습니다에 의해 다음 3
$ manipulate -in someimage.tif -m 2 -a 3

-in 옵션은로드 추가 내용을 벡터에 넣는다 current_image이고, 명령 행의 각 옵션은 current_image을 수정합니다.

그러나 variable_map 컨테이너는 옵션이 추가되는 순서를 유지하지 않습니다. 적어도 명시 적으로는 아닙니다. this post의 대답은 내가 염두에 두는 것에 가장 가깝지만, extra parsing code needed의 양은 getopt()과 거의 같습니다.

부스트 제공 컨테이너에 프로그램 옵션의 순서를 저장하는 방법을 아는 사람이 있습니까? 근본적으로 불가능한가요? 또는 시퀀스 컨테이너를 사용하여 구현할 수 있습니까?

EDIT 1 나는 really old post이 유효하다는 것을 알았습니다. 그렇습니다. 그렇다면 variables_map을 반복 할 수 있습니다. 물론 순서는 실제로 컴파일러 작성자에게 남겨진 명령 행의 순서와 동일하게 지정되지 않으므로 여전히 해킹으로 분류됩니다.
EDIT 2 옵션이 옵션 문자열별로 정렬되므로 반복 순서가 삽입 순서와 같지 않으므로 충분하지 않습니다.

답변

1

실제로 당신이 가지고있는 것은 표현 문법에 가깝습니다. 대신에 program_options를 사용하여 (ab?) 문법/파서를 작성하는 것이 좋습니다.

  • 프로그램에 옵션이있는 경우 : 프로그램 옵션을 사용하십시오.

  • 프로그램에서 표현식을 사용하는 경우 : 표현식 구문 분석기를 사용하십시오.

예 :

Live On Coliru

// #define BOOST_SPIRIT_DEBUG 
#include <boost/fusion/adapted/struct.hpp> 
#include <boost/fusion/include/io.hpp> 
#include <boost/spirit/include/qi.hpp> 

namespace qi = boost::spirit::qi; 

struct Operation { 
    enum Kind { add, multiply } kind; 
    double operand; 

    friend std::ostream& operator<<(std::ostream& os, Kind k) { 
     switch (k) { 
      case add:  return os << "--add"; 
      case multiply: return os << "--multiply"; 
     }; 
     return os << "??"; 
    } 
}; 

BOOST_FUSION_ADAPT_STRUCT(Operation, (Operation::Kind,kind)(double,operand)) 

template <typename It, typename Skipper = qi::blank_type> 
    struct expression_grammar : qi::grammar<It, std::vector<Operation>(), Skipper> { 
     expression_grammar() : expression_grammar::base_type(start) { 
      using namespace qi; 

      opkinds.add 
       ("-a",   Operation::add) 
       ("--add",  Operation::add) 
       ("-m",   Operation::multiply) 
       ("--multiply", Operation::multiply) 
       ; 

      option = opkinds > eol > double_; 

      start = *(option > eol); 

      BOOST_SPIRIT_DEBUG_NODES((start)(option)) 
     } 
    private: 
     qi::symbols<char, Operation::Kind> opkinds; 
     qi::rule<It, Operation(), Skipper> option; 
     qi::rule<It, std::vector<Operation>(), Skipper> start; 
    }; 

int main(int argc, char const** argv) { 
    std::stringstream iss; 
    if (argc) 
     std::copy(argv+1, argv+argc, std::ostream_iterator<const char*>(iss, "\n")); 

    typedef boost::spirit::istream_iterator It; 
    expression_grammar<It> grammar; 

    It first(iss >> std::noskipws), last; 
    std::vector<Operation> operations; 
    bool ok = qi::phrase_parse(first, last, grammar, qi::blank, operations); 

    if (ok) 
    { 
     std::cout << "Parse success\n"; 
     for (auto const& op : operations) 
      std::cout << boost::fusion::as_vector(op) << "\n"; 
    } else 
     std::cout << "Parse failed\n"; 

    if (first!=last) 
     std::cout << "Remaining input: '" << std::string(first,last) << "'\n"; 
} 

  • 내가 무상 옵션 구분 기호로 eol을 사용하려면 선택합니다.대신 '\0'을 사용할 수도 있습니다. blank 선장이 공백/스킵/eol을 이미 건너 뛰었 기 때문에 이것은 가장 쉬웠습니다. 나는 게으르다.
  • 당신은 mix-and-match (모든 매개 변수를 표현의 일부로 취급하지 않음)로 만들 수도있다.

    myprogram -e 'add 5; multiply 32;' -x option1 
    

    내가 다시 게으른이 방법 Live on Coliru 너무

  • 참조 : 일반적인 패턴은

    myprogram -x option1 -v -o filename -- my expression grammar follows 
    

    일반적인 다른 패턴 표현식을 하나의 매개 변수를 확인하는 것입니다 것 "구문 분석 성공"인쇄 (Operation 유형의 경우 operator<<을 구현하고 싶지 않음)

  • 01 23,516,
  • #define BOOST_SPIRIT_DEBUG와 디버그 정보 (첫 번째 줄의 주석)

    <start> 
        <try>-a\n8\n-m\n7\n-a\n32\n</try> 
        <option> 
        <try>-a\n8\n-m\n7\n-a\n32\n</try> 
        <success>\n-m\n7\n-a\n32\n</success> 
        <attributes>[[--add, 8]]</attributes> 
        </option> 
        <option> 
        <try>-m\n7\n-a\n32\n</try> 
        <success>\n-a\n32\n</success> 
        <attributes>[[--multiply, 7]]</attributes> 
        </option> 
        <option> 
        <try>-a\n32\n</try> 
        <success>\n</success> 
        <attributes>[[--add, 32]]</attributes> 
        </option> 
        <option> 
        <try></try> 
        <fail/> 
        </option> 
        <success></success> 
        <attributes>[[[--add, 8], [--multiply, 7], [--add, 32]]]</attributes> 
    </start> 
    Parse success 
    (--add 8) 
    (--multiply 7) 
    (--add 32) 
    
+0

추가 너무 하나의 인자 발현 접근을 가능하게 ([coliru] (http://coliru.stacked-crooked.com/a/0a4aca0d42a477b7)) – sehe

+0

아름다운! 주문 (컨텍스트)이 문제가되는 시점에서 작업 순서를 표현식으로 처리하는 것은 프로그램 옵션이 잘 적용되지 않는 것입니다. 그렇더라도 순서가 알려지지 않은 경우 결과가 예측할 수없는 여러 번 발생 (예 : --verbose on --verbose off)에 대한 program_options가 지원됩니다. 순서가 유지되고 구문 분석이 평평하게 유지되면 (괄호는 허용되지 않음) 이러한 작업을 프로그램 옵션으로 처리하는 것은 문제가되지 않습니다. 아직도,이 예제에 대해 많은 감사를드립니다! –