숫자와 수학 표현식 만 포함하는 매우 단순한 언어에 대한 매우 간단한 구문 분석기를 만들려고합니다. 궁극적으로이 확장을 계획하지만이 기본 버전을 작동시킬 때까지는 아닙니다.반복적 인 Spirit.Qi 문법으로 인한 세그먼트 오류
가 나는 성공적으로 분석했습니다
1
425
1 + 1
1 - 1
1 * 1
1/1
없음 문제. 하지만 다음과 같이 입력을 구문 분석하여 재귀 적으로 만들고 싶었습니다.
1 + 2 - 3
세그먼트 화 오류가 발생하기 시작했습니다. 재귀 문법과 세분화 오류로 인해 인터넷 검색을 한 적이 있습니다. 발견 한 내용을이 문법에 적용하여 작동시키지 못하는 것 같습니다. 이것은 제 상황에 어울리지 못하거나 제 qi 문법에 어떤 일이 일어나고 있는지 정확하게 이해하지 못하기 때문입니다.
내 문법 (융합 적응 포함) 다음과 같은 구조체로 구성
namespace fun_lang {
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
namespace fusion = boost::fusion;
struct number_node {
long value;
};
struct operation_node;
typedef boost::variant<
boost::recursive_wrapper<operation_node>,
number_node
> node;
struct operation_node {
node left, right;
char op;
};
struct program {
std::vector<node> nodes;
};
}
BOOST_FUSION_ADAPT_STRUCT(fun_lang::program, (std::vector<fun_lang::node>, nodes));
BOOST_FUSION_ADAPT_STRUCT(fun_lang::number_node, (long, value));
BOOST_FUSION_ADAPT_STRUCT(fun_lang::operation_node, (fun_lang::node, left) (char, op) (fun_lang::node, right));
namespace fun_lang {
template <typename Iterator, typename Skipper>
struct fun_grammar : qi::grammar<Iterator, program(), Skipper> {
fun_grammar() : fun_grammar::base_type(start) {
using ascii::char_;
using qi::ulong_;
using qi::_val;
using qi::_1;
using phoenix::push_back;
using phoenix::at_c;
expression = (integer | operation)[_val = _1];
oper = (char_('+') | char_('-') | char_('*') | char_('/'))[_val = _1];
integer = ulong_[at_c<0>(_val) = _1];
operation = expression[at_c<0>(_val) = _1] >> oper[at_c<1>(_val) = _1] >> expression[at_c<2>(_val) = _1];
start = *expression[push_back(at_c<0>(_val), _1)];
}
qi::rule<Iterator, program(), Skipper> start;
qi::rule<Iterator, number_node(), Skipper> integer;
qi::rule<Iterator, char(), Skipper> oper;
qi::rule<Iterator, node(), Skipper> expression;
qi::rule<Iterator, operation_node(), Skipper> operation;
};
}
규칙 구조의 일부는 내가하는 방법에 대한 참조로 사용 된 다른 언어로 쓴 yacc에 문법을 기반으로 이러한 규칙을 구조화합니다. 세분화 오류를 일으키는 것이 무엇인지 모르겠지만이를 실행할 때 나는 그것이 무엇인지 알 수 있습니다. 규칙 단순화, 중간 규칙 제거 및 비 재귀 메서드 테스트를 시도했습니다. 재귀가 아닌 것은 작동하는 것처럼 보이지만 재귀 규칙을 사용하여 Spirit의 많은 예를 보았 기 때문에 성공한 규칙을 표현하는 방법을 제대로 이해하지 못했다고 생각합니다.
편집이 ideone에 대부분의 정확한 복사본을 찾을 수있는 문제 해결에 도움을 들어
. 이데온 버전과 내가 로컬에 가지고있는 유일한 차이점은 표준 입력에서 직접 가져 오는 파일을 읽는 대신에 가능하다는 것입니다.
흠. LL 파서가 복잡한 언어를 정의 할 때 약한 것처럼 보입니다. 그러나 스피릿에 대한 (매우 기본적인) 경험으로 복잡한 구문보다는 간단한 구문 분석 문제를 해결할 수 있다고 생각합니다. –
나는 그것을 말하지 않을 것이다. LALR 파서는 LL 파서 (그리고 LR 파서가 여전히 강력 함)보다 강력하고 효율적인 반면, Boost.Spirit은 매우 강력합니다. 무한한 선견자와 모든 것. 야생에서 발견 할 수있는 대부분의 언어는 LL 파서로 파싱 할 수 있으며 LL (inf)로도 편리하게 사용할 수 있습니다. 왼쪽 재귀 문법을 공식화하지 않는 것이 LALR로 처리 할 필요가없는 LL 파서로 처리해야하는 유일한 중요한 것입니다. – Wintermute
둘을 구분하는 데 더 많은 시간을 할애해야합니다. 나는 파싱과 문법 그리고 모든 좋은 것들에 관해서는 상당히 초록색이다. 위대한 답변을 주셔서 감사합니다, 그것은 입력을 위해 일했습니다. 지금은 (1 + 2) + 10을 위해 어디로 가야할 지 모르겠지만 좀 더 읽고 마음껏 시도 할 것입니다. –