문제

나는 모호성이 없다는 것을 알고있는 문법에 대한 교대/감소 confict를 이해하는 데 문제가 있습니다. 이 사례는 IF Else 유형 중 하나이지만 필수 엔드 조항이 코드 블록을 구분하는 것이기 때문에 '끊임없는 다른'문제는 아닙니다.

GPPG 용 문법은 다음과 같습니다 (소년은 컴파일러 컴파일러와 유사한 소비자가 아니 었습니다).

%output=program.cs

%start program

%token FOR
%token END
%token THINGS
%token WHILE
%token SET
%token IF
%token ELSEIF
%token ELSE
%%

program : statements
        ;

statements : /*empty */
           | statements stmt
           ;

stmt : flow
     | THINGS
     ;

flow : '#' IF '(' ')' statements else
     ;

else : '#' END
     | '#' ELSE statements '#' END
     | elseifs
     ;

elseifs : elseifs '#' ELSEIF statements else
        | '#' ELSEIF statements else
        ;

충돌 출력은 다음과 같습니다.

// Parser Conflict Information for grammar file "program.y"

Shift/Reduce conflict on symbol "'#'", parser will shift
 Reduce 10: else -> elseifs
 Shift "'#'":   State-22 -> State-23
  Items for From-state State 22
    10 else: elseifs .
    -lookahead: '#', THINGS, EOF
    11 elseifs: elseifs . '#' ELSEIF statements else 
  Items for Next-state State 23
    11 elseifs: elseifs '#' . ELSEIF statements else 

// End conflict information for parser

나는 이미 모든 것을 바꾸었고 그것을 해결하는 방법을 알고 있지만, 그 해결책에는 오른쪽 재귀를 위해 'elseif'에 왼쪽 재귀를 포기하는 것이 포함됩니다.

이 문제에 관해 인터넷에서 찾은 모든 흉터 문서를 살펴 보았지만 (마지막에 일부 링크를 게시 함) 여전히 우아한 솔루션을 찾지 못했습니다. 나는 Antlr에 대해 알고 있으며 지금 당장 고려하고 싶지 않습니다. 솔루션을 YACC/Bison Parsers로 제한하십시오.

나는 우아한 솔루션에 감사 할 것이며, 나는 빈 * / 규칙과 복제를 기울여 공허한 목록이 필요한 모든 것을 명확히함으로써 그것을 할 수 있었지만, 더 큰 문법에서 작업하는 것은 'sparghetti 문법 증후군'처럼 끝납니다.

다음은 몇 가지 링크입니다.

http://nitsan.org/~maratb/cs164/bison.html

http://compilers.iecc.com/comparch/article/98-01-079

GPPG, 내가 사용하는 구문 분석기

들소 매뉴얼

도움이 되었습니까?

해결책

개정 된 elseif 규칙에는 조건에 대한 마커가 없습니다. 명목상 '('and ')'추가해야합니다.

더 진지하게, 당신은 이제 규칙을 가지고 있습니다

elsebody : else
         | elseifs else
         ;

그리고

elseifs : /* Nothing */
        | elseifs ...something... 
        ;

'아무것도'필요는 없습니다. 그것은 'elseifs'없이 'elsebody'에 의해 암시 적으로 처리됩니다.

나는 규칙 'opt_elseifs', 'opt_else'및 'end'를 사용하는 경향이 있습니다.

flow : '#' IF '(' ')' statements opt_elseifs opt_else end
     ;

opt_elseifs : /* Nothing */
            | opt_elseifs '#' ELSIF '(' ')' statements 
            ;

opt_else : /* Nothing */
         | '#' ELSE statements
         ;

end : '#' END
    ;

파서 생성기를 통해 이것을 실행하지는 않지만 비교적 이해하기 쉽습니다.

다른 팁

문제는 elseifs 절에 있다고 생각합니다.

elseifs : elseifs '#' ELSEIF statements else
        | '#' ELSEIF statements else
        ;

else 절은 어쨌든 elseifs를 다시 언급하기 때문에 첫 번째 버전은 필요하지 않다고 생각합니다.

else : '#' END
     | '#' ELSE statements '#' END
     | elseifs
     ;

elseifs를 바꾸면 어떻게됩니까? :

elseifs : '#' ELSEIF statements else
        ;

위의 Jonathan의 답변은 그것이 최고가 될 것 같지만, 당신을 위해 작동하지 않기 때문에 오류를 디버깅하는 데 도움이 될 몇 가지 제안이 있습니다.

먼저 해시/샤프 기호를 토큰 자체의 일부로 만드는 것을 고려 했습니까 (예 : #end, #if 등)? 그들이 Lexer에 의해 꺼지기 때문에, 그들은 파서에 포함될 필요가 없다는 것을 의미합니다.

둘째, 토큰 스트림을 복제하지 않고 규칙을 다시 작성할 것을 촉구합니다. (원칙을 반복하지 마십시오.) 따라서 규칙 " '#'elseif 문"은 해당 파일의 한 곳에 만 존재해야합니다 (위와 같이 두 개가 아닙니다).

마지막으로 나는 당신이 if/elseif/else 토큰의 우선 순위와 연관성을 조사 할 것을 제안합니다. 나는 당신이 이것을 요구하지 않는 파서를 쓸 수 있어야한다는 것을 알고 있지만,이 경우 필요한 것일 수 있습니다.

나는 아직도 아라운드를 바꾸고 있는데, 내 원래 질문은 elseifs 시퀀스는 또 다른 끝이 끝났습니다. 질문에 대한 또 다른 테이크는 다음과 같습니다. 이번에는 두 가지 교대/분쟁이 줄어 듭니다.

flow : '#' IF '(' ')' statements elsebody 
     ;

elsebody : else 
         | elseifs else
         ;

else : '#' ELSE statements '#' END
     | '#' END
     ;

elseifs : /* empty */
        | elseifs '#' ELSEIF statements
        ;

이제 갈등은 다음과 같습니다.

// Parser Conflict Information for grammar file "program.y"

Shift/Reduce conflict on symbol "'#'", parser will shift
 Reduce 12: elseifs -> /* empty */
 Shift "'#'":   State-10 -> State-13
  Items for From-state State 10
    7 flow: '#' IF '(' ')' statements . elsebody 
    4 statements: statements . stmt 
  Items for Next-state State 13
    10 else: '#' . ELSE statements '#' END 
    11 else: '#' . END 
    7 flow: '#' . IF '(' ')' statements elsebody 

Shift/Reduce conflict on symbol "'#'", parser will shift
 Reduce 13: elseifs -> elseifs, '#', ELSEIF, statements
 Shift "'#'":   State-24 -> State-6
  Items for From-state State 24
    13 elseifs: elseifs '#' ELSEIF statements .
    -lookahead: '#'
    4 statements: statements . stmt 
  Items for Next-state State 6
    7 flow: '#' . IF '(' ')' statements elsebody 

// End conflict information for parser

빈 규칙은 내가 두드리는 GPPG를 악화시킵니다. 그러나 그들은 계속 사용하는 데 너무 자연스럽게 보입니다.

나는 이미 올바른 재귀가 문제를 해결한다는 것을 알고 있습니다 1800 정보 말했다. 그러나 나는 해결책을 찾고 있습니다 왼쪽 재귀elseifs 절.

elsebody : elseifs else
         | elseifs
         ;

elseifs : /* empty */
        | elseifs '#' ELSEIF statements
        ;

else : '#' ELSE statements '#' END
     ;

나는 이것이 되풀이되고 항상 종료되어야한다고 생각합니다.

OK- 여기에 IF 블록을위한 문법 (최소화되지 않음)이 있습니다. 나는 내가 가지고있는 일부 코드에서 파헤 쳤다 (Kernighan & Plauger의 "Unix 프로그래밍 환경"의 HOC를 기반으로 ADHOC라고 함). 이 개요는 문법이 충돌없이 YACC와 컴파일됩니다.

%token  NUMBER IF ELSE
%token  ELIF END
%token  THEN
%start program

%%

program
    :   stmtlist
    ;

stmtlist
    :   /* Nothing */
    |   stmtlist stmt
    ;

stmt
    :   ifstmt
    ;

ifstmt
    :   ifcond endif
    |   ifcond else begin
    |   ifcond eliflist begin
    ;

ifcond
    :   ifstart cond then stmtlist
    ;

ifstart
    :   IF
    ;

cond
    :   '(' expr ')'
    ;

then
    :   /* Nothing */
    |   THEN
    ;

endif
    :   END IF begin
    ;

else
    :   ELSE stmtlist END IF
    ;

eliflist
    :   elifblock
    |   elifcond eliflist begin         /* RIGHT RECURSION */
    ;

elifblock
    :   elifcond else begin
    |   elifcond endif
    ;

elifcond
    :   elif cond then stmtlist end
    ;

elif
    :   ELIF
    ;

begin
    :   /* Nothing */
    ;

end
    :   /* Nothing */
    ;

expr
    :   NUMBER
    ;

%%

나는 '숫자'를 사물 대신 더미 요소로 사용했고 elseif 대신 elif를 사용했습니다. 그때는 포함되지만 선택 사항입니다. '시작'및 'END'작업은 생성 된 프로그램에서 프로그램 카운터를 잡는 데 사용되었으므로 영향을 미치지 않고 제거 할 수 있어야합니다.

정상적인 왼쪽 재귀 대신 올바른 재귀를 사용해야한다고 생각한 이유가 있었지만 다른 무엇보다도 사용했던 코드 생성 전략과 관련이 있다고 생각합니다. 주석의 물음표는 원본에있었습니다. 나는 그것에 만족하지 않는 것을 기억합니다. 전체적으로이 프로그램은 작동합니다 - 지난 10 년 동안 백 버너에 있던 프로젝트입니다 (흠 ... 2004 년 말과 2005 년 초에 일을했습니다. 그 전에는 1992 년이었습니다. 및 1993).

나는 이것이 왜 충돌이없고, 앞에서 설명한 내용이 아닌지를 해결하는 데 시간을 보냈다. 도움이되기를 바랍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top