소 시 부 스 트 정신
구출 방법 은 도 구 를 통 해 파 서 를 생 성 하 는 것 이다. 이 방면 에는 비교적 유명한 도구 가 많다. 예 를 들 어 Lex, Yacc, ANTLR 등 이다. 그들의 기능 은 대동소이 하 다. 모두 문법 (EBNF 로 설명) 을 바탕 으로 해당 하 는 파 서 로 전환 된다. 그러나 이런 도 구 는 사용 하기에 비교적 번거롭다. 먼저 생 성 된 코드 는 가 독성 이 좋 지 않다.또한 이 코드 를 프로젝트 에 넣 으 려 면 생 성 된 코드 를 수정 해 야 하기 때문에 문법 이 바 뀌 면 parser 가 다시 생 성 되 어야 합 니 다. 이런 수정 은 기본적으로 다시 해 야 하기 때문에 유지 하기 가 어렵 습 니 다.
그렇다면 이 도구 들 외 에 다른 해결 방안 은 없 을 까?아마도 너 는 boost spirit 을 시도 해 볼 수 있 을 것 이다.
다음 내용 은 boost 1.37.0 을 바탕 으로 spirit 의 버 전 은 1806 이 고 오래된 버 전 입 니 다. 최신 버 전에 비해 원 리 는 많 지 않 지만 라 이브 러 리 의 디 렉 터 리 구 조 는 많이 다 르 기 때문에 알 고 있 습 니 다.
Spirit 이 뭐 예요?
쉽게 말 하면 Spirit 은 parser generator 입 니 다. 기능 은 Yacc, ANTLR 과 유사 하고 EBNF 를 바탕 으로 문법 을 묘사 한 다음 에 문법 을 바탕 으로 parser 를 생 성 합 니 다. 그러나 앞의 도구 에 비해 가장 큰 차이 점 은 C + 코드 를 사용 하여 문법 을 묘사 하고 매우 잔인 한 템 플 릿 프로 그래 밍 기법 을 통 해컴 파일 단계 에서 해당 하 는 parser 가 생 성 되 었 습 니 다.사용자 의 측면 에서 볼 때 문법 은 코드 로 설명 되 기 때문에 현재 프로젝트 에 직접 가입 하여 기 존 코드 와 결합 할 수 있 습 니 다.
물론 Spirit 의 문법 은 형식적 으로 EBNF 에 약간의 차이 가 있다. 예 를 들 어 '>' 로 서로 다른 표현 식 을 연결 하고 중복 되 는 기 호 를 표현 식 의 앞 에 두 었 다 는 것 을 나타 내 는 등 은 모두 c + 문법 에 의 해 제 한 된 절충 이 고 문법 적 의 미 는 변 하지 않 았 다.
첫 체험
EBNF 로 설명 하면 다음 과 같은 전형 적 인 정수 사 칙 연산 을 쓸 수 있 습 니 다.
group ::= '(' expression ')'
factor ::= integer | group
term ::= factor (('*' factor) | ('/' factor))*
expression ::= term (('+' term) | ('-' term))*
그 중에서 group, factor, term, expression 은 각각 하나의 rule 이 라 고 부 르 는데 해당 하 는 텍스트 와 어떻게 일치 하 는 지 나타 내 는 데 사용 된다. 상기 EBNF 문법 은 Spirit 에서 다음 과 같은 형식 으로 쓸 수 있다.
group = '(' >> expression >> ')';
factor = integer | group;
term = factor >> *(('*' >> factor) | ('/' >> factor));
expression = term >> *(('+' >> term) | ('-' >> term));
문법 차이 가 많 지 않 은 것 같 습 니 다. 다만 연산 자 는 약간 다 릅 니 다. 지적 해 야 할 것 은 Spirit 에서 하나의 rule 은 parser 대상 입 니 다. 하나의 parser 대상 은 해당 하 는 문법 규칙 을 포함 하여 이 parser 는 이러한 규칙 에 부합 되 는 텍스트 만 parse 할 수 있 습 니 다. 예 를 들 어 우 리 는 지금 parse 에서 쉼표 로 구 분 된 정수 (CSV) 를 내 고 싶 습 니 다.다음 rule 을 정의 할 수 있 습 니 다.
boost::spirit::rule<> csv_int = int_p >> *(',' >> int_p);
상기 코드 중, intp 는 Spirit 내 에 만들어 진 rule 또는 parser 입 니 다. 이 parser 는 parse 의 전체 형 (int p 를 제외 하고 Spirit 은 parse 의 다른 기본 데이터 형식 에 사용 되 는 일련의 parser 를 만 들 었 습 니 다. 구체 적 인 목록 은 여 기 를 참고 하 십시오).parser 와 parser 는 ">" 연산 자 를 통 해 연결 한 후 새로운 parser 를 구성 하 였 습 니 다. 그러면 csv 를 어떻게 사용 합 니까?int 이 새로 생 성 된 parser 는?Spirit 내 에 함 수 를 정 의 했 습 니 다. 원형 은 다음 과 같 습 니 다.
boost::spirit::parse_info<> parse(const char* text, parser, separator);
parse () 함 수 를 호출 하여 parse 가 필요 한 텍스트 와 해당 하 는 parser 를 입력 하면 이 텍스트 에 대해 해당 하 는 설명 을 할 수 있 습 니 다. 결 과 를 되 돌려 주 는 과정 이 성 공 했 는 지, 그리고 오류 가 발생 하면 어느 위치 에서 오류 가 발생 했 는 지 알려 줍 니 다.
Semantic actions
앞에서 정의 한 csvint 라 는 parser 는 문법 을 정 의 했 지만 아무것도 하지 않 았 습 니 다. 특정한 텍스트 가 쉼표 로 구 분 된 정형 인지 확인 하 는 데 만 사용 할 수 있 습 니 다. 기능 이 너무 약 합 니 다. 일반적으로 우 리 는 텍스트 에서 데 이 터 를 추출 해 야 하기 때문에 parse 의 과정 은 특정한 동작 을 지원 해 야 합 니 다. 우 리 는 parser 가 parse 에서 어떤 내용 을 추출 해 야 할 때,사용자 가 지정 한 행동 동작 을 수행 할 수 있 습 니 다. Spirit 에서 이 동작 을 semantic action 이 라 고 합 니 다.
Semantic action 은 parser 에 속 합 니 다. 이 parser 가 성공 한 후에 어떤 작업 을 수행 해 야 하 는 지 를 가리 키 는 데 의미 가 있 습 니 다. 이 작업 들 은 사용자 가 지정 한 것 입 니 다.우 리 는 다음 과 같은 방식 으로 semantic action 을 parser 와 연결 할 수 있 습 니 다.
parser[func];
func 의 원형 에 대해 서 는 당연히 요구 가 있 습 니 다. 그리고 이것 은 구체 적 인 parser 를 봐 야 합 니 다. 예 를 들 어 intp 와 같은 parser 는
void func(const int val);
와 같은 함수 만 받 아들 일 수 있 고 간결 한 문법 입 니 다!이제 우 리 는 앞에서 정형 을 설명 하 는 코드 에 새로운 기능 을 추가 합 니 다. parse 가 모든 정형 을 완성 한 후에 우리 가 얻 은 데 이 터 를 저장 합 니 다.#include
#include
#include
#include
#include
std::vector g_output;
int on_parse_int(const int val)
{
g_output.push_back(val);
}
int main()
{
boost::spirit::rule<> int_csv_rule = int_p[on_parse_int] >> *(',' >> int_p[on_parse_int]);
boost::spirit::parse("2,3,4", int_csv_rule);
return 0;
}
semantic action 의 실현 은 boost 에서 또 다른 명성 이 자자 한 함수 식 템 플 릿 라 이브 러 리 에 의존 합 니 다. phoenix, 위의 예 는 간단 한 시범 일 뿐 빙산 의 일각 에 미 치지 못 합 니 다. spirit 은 lambda 로 리 셋 함 수 를 쓰 는 것 을 지원 합 니 다. 그리고 서로 다른 rule 사이 에 사용자 가 정의 하 는 문맥 정 보 를 전달 하 는 등 기능 이 매우 강 합 니 다.관심 이 있 는 독 자 는 이곳 의 상대 적 인 완전 점 의 예 를 참고 하여 간단 한 네 가지 연산 과 기본 적 인 함수 호출 을 실현 할 수 있다.
생 성 된 Parser 의 종류
Parser 는 전체 Spirit 라 이브 러 리 의 핵심 기능 입 니 다. 그렇다면 Spirit 이 생 성 한 parser 는 어떻게 일 을 합 니까?결론 은 spirit 이 생 성 한 parser 는 이른바 LL recursive decent parser 이다. 따라서 parse 는 왼쪽 에서 오른쪽으로 스 캔 하여 입력 하고 parser 의 문법 에 대해 왼쪽, 오른쪽 순 서 를 매 칭 하기 때문에 왼쪽 재 귀 와 같은 문 제 는 사용자 가 스스로 제거 해 야 한다. 다음 과 같은 예 를 들 어:
rule<> rule1 = (int_p >> ',' >> int_p) | real_p;
rule 1 은 parse 텍스트 에 있 을 때 우선 일치 합 니 다 (int p > >, > int p). 실패 하면 real 와 일치 합 니 다.p。
장단 점
이 라 이브 러 리 를 사용 한 시간 이 그리 길지 않 기 때문에 초보 적 인 느낌 이 들 고 장점 에 있어 서 개인 적 으로 다음 과 같은 몇 가지 가 있다 고 생각 합 니 다.
결론 은 좋 고 강하 지만 단점 도 뚜렷 하 다.
[참고]
http://boost-spirit.com/distrib/spirit_1_8_3/libs/spirit/doc/quick_start.html http://en.highscore.de/cpp/boost/
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.