2011-07-26 3 views
1

Bison을 사용하여 C++에서 파서를 생성하려고합니다. 문법은 괜찮지 만, 나는 그 행동에 약간의 문제가있다. 다음은 간단한 샘플입니다.Bison의 작업 순서

statements 
: statement 
| statements statement; 

제가 아는 한, 이것은 매우 일반적인 일입니다. 내가 가진 질문은 먼저 파생 된 것입니다. 예를 들어, 나는 들소가

statement (statement (statement (statement)))) 

또는

(((statement) statement) statement) statement 

나는의 연결리스트를 구축하기 위해 노력하고있어 나의 행동을 호출 않습니다

statement statement statement statement 

처럼 보이는 입력이있는 경우 여기에서 규칙이 호출되며 입력 한 순서와 동일한 순서로 목록을 유지하려고합니다. OK, 그래서이 뭔가를 할 수 있습니다 : 바로 지금, 나는

statements 
: statement 
{ 
    $$ = $1; 
} 
| statements statement 
{ 
    dynamic_cast<ParsedFile::Statement*>($1)->Next = dynamic_cast<ParsedFile::Statement*>($2); 
    $$ = $1; 
}; 

편집있어

switch_statement 
: SWITCH '(' expression ')' 
{ 
    auto Switch = p.Make<ParsedFile::SwitchStatement>(); 
    Switch->Test = dynamic_cast<ParsedFile::Expression*>($3); 
    p.NewScope(); 
    $$ = Switch; 
} 
'{' case_statements '}' 
{ 
    auto Switch = dynamic_cast<ParsedFile::SwitchStatement*>($5); 
    Switch->Cases = p.statements.top(); 
    p.PopScope(); 
    p.AddToCurrentScope(Switch); 
}; 

default_statement 
: DEFAULT ':' 
{ 
    auto Default = p.Make<ParsedFile::DefaultStatement>(); 
    p.NewScope(); 
    $$ = Default; 
} 
statements 
{ 
    auto Default = dynamic_cast<ParsedFile::DefaultStatement*>($3); 
    Default->Statements = p.statements.top(); 
    p.PopScope(); 
    p.AddToCurrentScope(Default); 
}; 

case_statement 
: CASE expression 
{ 
    auto case = p.Make<ParsedFile::CaseStatement>(); 
    p->Value = dynamic_cast<ParsedFile::Expression*>($2); 
    p.NewScope(); 
    $$ = case; 
} 
DOUBLE_COLON statements 
{ 
    auto Case = dynamic_cast<ParsedFile::CaseStatement*>($3); 
    Case->Statements = p.statements.top(); 
    p.PopScope(); 
    p.AddToCurrentScope(Case); 
}; 

case_statements 
: case_statement 
| case_statements case_statement 
| case_statements default_statement; 
+0

왜 downvote? – Praetorian

+0

@DeadMG :'$ 2'를'$ 1'에 추가하고'$$'을 통해'$ 1'을 "return"하기 때문에 다음 파생 이후 같은 노드의'Next' 포인터를 * 리셋 할 것입니다. 링크 된리스트를 필사적으로 원한다면 (왜 '벡터'또는 'deque'가 아닌가?), 머리와 꼬리 모두에 대한 포인터를 유지해야한다. –

+0

@larsmans : 내가 의존 할 수있는 곳을 저장하지 않았기 때문에 저는 벡터 또는 양면 기준을 사용하지 않습니다. 스택 (C 스타일 문법)에 여러 개의 'statement'가있을 수 있으며 Bison은 복잡한 컨테이너를 지키지 않습니다. 사실, 생각해 보니, 실제로 스택이 될 것이라고 결코 짐작하지 않았습니다. 그래서 나는 사용자 정의 인수에이를 저장할 수 있었고, 중간 규칙 인수를 사용하여 밀어 넣고 팝했습니다. – Puppy

답변

4

그것은 왼쪽으로 연관, 즉

(((statement) statement) statement) statement 

당신은 말할 수 이것이 유일한 가능성인데 이는 이것을 작품 중 하나 인 statements statement으로 줄일 수 있기 때문입니다.

statement (statement (statement (statement)))) 

다른 옵션은 제작의 하지 하나입니다 statement statements, 감소되어야 할 것이다. 그러나 대신 오른쪽 연관성을 원한다면 이것을 사용할 수 있습니다.

다른 하나의 문에 가입 한 후, 당신은 문에 대한 포인터를 반환하기 때문에, 그래서 다음 문 주위에 당신이 Next 포인터를 덮어하고 오는대로-때 링크 된 목록을 생성하지 않습니다 귀하의 코드 첫 번째 진술의

순서를 오른쪽 연관으로 변경하면 문제를 해결할 수 있지만 구문의 개수에 선형 파서 스택 공간이 필요합니다. 많은 진술을 기대한다면 연결 목록을 역으로 작성하는 것을 고려해야합니다.

+0

입력 해 주셔서 감사합니다. 같은 문제에 대한 다른 전략을 반영하기 위해 OP를 편집했습니다. 귀하의 답변에 감사드립니다. 그렇지 않다면 원래 질문에 대답 할 때 대답을 받아 들일 것입니다. – Puppy

+0

@DeadMG : 나는 행동의 상태 코드를 쓰는 것을 피하는 경향이 있습니다. 사물의 순서를 따르는 것이 어려울 수 있기 때문입니다. '$$ = foo ($ 1, $ 2)'형태로 행동을 작성하는 것을 고려하십시오. 그러면 순서는'foo (foo (foo (bar (first), second), 세번째), 네번째 (')라고 쓰는 것과 같습니다. – hammar

+0

스코프에는 올바른 범위를 결정하기 위해 그런 종류가 필요합니다. 다른 방법으로 생각한 것은 실용적이지 않다고 생각합니다. 그러나 표현식과 같은 범위가없는 구문의 경우, 이는 상태가 아닌 기능적으로 작성됩니다. – Puppy