2017-11-05 12 views
0

작은 파서를 쓰려고합니다. 불행히도 "교대 감소 충돌"이 발생합니다. 문법은 저의 강점이 아니며,이 문구를 약간만 해 주면됩니다. 오류를 생성하는 축소 된 문법은 다음과 같습니다.Shift/내 문법의 IF-ELSE 충돌을 줄입니다.

stmts_opt -> stmts 
; 

stmts -> stmt 
| stmts stmt 
| stmsts 
; 

stmt -> id 
| ITERATE content_stmt 
| IF test then content_stmt ELSE content_stmt 
| IF test then content_stmt 
; 

content_stmt: BEGIN stmt_opt END 
| stmt 
; 

수정 된 문법을 제공하는 솔루션은 높이 평가할 수 있습니다.

편집 : 내 문법 RICI의 대답 @ 양복지하지만 문제가 계속 수정

.

BEGINNING-OF-PROGRAM 
    BEGINNING-OF-EXECUTION 

    IF not-next-to-a-beeper THEN 
     move; 

    IF not-facing-north THEN 

     turnleft; 


    ELSE <--- ERROR 
     turnleft; 

    IF not-facing-east THEN 
     IF not-facing-west THEN 
     turnleft; 

    turnoff 
    END-OF-EXECUTION 
END-OF-PROGRAM 

내가 처음 ELSE에 오류가 점점 오전 : 여기

prog: BEGIN_PROG def_sprogram BEGIN_EXEC stmts_opt END_EXEC END_PROG 
      {() } 
; 

def_sprogram: /* empty */  {() } 
| define_new def_sprogram  {() } 
; 


define_new:   DEFINE_NEW_INSTRUCTION ID AS content_stmt SEMI { } 
; 

stmts_opt: /* empty */  {() } 
|   stmts   {() } 
; 

stmts:  stmt   {() } 
|   stmts SEMI stmt {() } 
|   stmts SEMI  {() } 
; 

content_stmt: BEGIN stmts_opt END {() } 
|  stmt {() } 
; 

stmt:  open_stmt {() } 
|   closed_stmt {() } 
; 

open_stmt: ITERATE INT TIMES open_stmt {() } 
|   WHILE test DO open_stmt {() } 
|   IF test THEN closed_stmt ELSE open_stmt {() } 
|   IF test THEN stmt {() } 
; 

closed_stmt: simple_stmt {() } 
|   ITERATE INT TIMES closed_stmt {() } 
|   WHILE test DO closed_stmt {() } 
|   IF test THEN closed_stmt ELSE closed_stmt {() } 
; 

내가가 테스트하고있는 예이다 : 여기 내 실제 문법 작품이다. 또한 @rici가 제안한 것처럼 간단한 우선 순위를 선언하려고 시도했습니다.

%nonassoc THEN 
%nonassoc ELSE 

그러나이 오류는 해결되지 않았습니다.

+0

yacc/bison이 올바른 해결 방법을 선택하기 때문에 shift-reduce 충돌 만이 else 애매함으로 인해 생기는 경우 문법이 올바르게 작동합니다. 경고를 없애려면 여기에서 "다른 것을 매달아"검색하십시오. – rici

+0

camlyacc를 사용하고 있으며 경고가 아닌 오류가 표시됩니다. 여기에서 검색하려했지만 문법이 약간 다릅니다 (BEGIN 및 END). 제안 된 해결책이 나에게 적합하지 않았습니다. –

+0

오류를 만드는 것은 짜증나게합니다. 그렇게해서는 안됩니다. 그러나 시작과 끝 토큰은 아무런 효과가 없어야합니다. 당신은 무엇을하지 않았습니까? – rici

답변

1

"dangling else"shift-reduce 충돌에 대한 가장 간단한 해결 방법은 ELSE 토큰을 이동하여 해상도를 강제로 변경하는 것입니다.

%nonassoc THEN 
%nonassoc ELSE 

(연관성의 아무튼를 : camlyacc이가 (첫 번째 %% 전에) 당신의 선언 섹션에 다음을 추가하는 것만 큼 간단해야한다 (I 찾을 수 있었다 오히려 스케치 설명서에 따라) 지원 우선 순위 선언을 수행하기 때문에

문법에 아무 것도 없기 때문에 문법에 아무 것도 없기 때문에 문제가되지 않습니다. 명시 적으로 "일치/일치하지 않는"(또는 "공개/폐쇄 문")을 사용하려면 BEGIN stmts_opt ENDTHEN을 허용 할 수 없으므로 "일치"(또는 "닫힌"문)입니다. 다른 일치하는 문은 타의 추종을 불허하는 문

unmatched_stmt: ITERATE unmatched_stmt 
       | IF test THEN matched_stmt 
       | IF test THEN unmatched_stmt 
       | IF test THEN matched_stmt ELSE unmatched_stmt 

많은 사람들이 matched_stmtunmatched_stmt을 포함하는 비 터미널을 생성하는 것을 선호 있습니다

matched_stmt: BEGIN stmts_opt END 
      | ITERATE matched_stmt 
      | IF test THEN matched_stmt ELSE matched_stmt 
      | /* Any other kind of simple statement */ 

이다. 그러나 귀하의 경우에는 둥지를 원하지 않는 것 같습니다 BEGIN & hellip; END 블록을 사용하여 이들을 복합 텍스트의 내용으로 제한합니다. 따라서 stmtBEGIN stmts_opt END 오른쪽의 경우을 제외한 일 수 있습니다.

+0

답변 해 주셔서 감사합니다. 나는 두 가지 해결책을 모두 시험해 보았고 둘 중 하나는 나를 위해 일했습니다. 나는 내가 어딘가에서 착각했다고 거의 확신한다. matched_stmt와 unmatched_stmt를 포함시킨 후 완전히 새로운 문법으로 질문을 업데이트했습니다. –

+0

@ Joker00 : 우리는 보통 [mcve]를 주장하는 이유와 왜 질문에 답을 한 후에 편집 질문을하지 않는 이유가 있습니다. 나는 내 대답이 당신의 파서를 만들려고 할 때보고 된 shift-reduce 충돌을 해결했다는 점에서 당신의 초기 질문에 정확하게 응답했다는 것을 확신한다. 편집 한 질문에서 * 다른 문법 * (세미콜론 문 구분 기호 포함)의 결과 인 * 다른 문제 * (파서 실행 중 구문 오류 *)를보고합니다. 세미콜론을 사용하면 구문 오류가 발생합니다 .... – rici

+0

... 'stmt'는 정의한대로 * 뒤에 꼬리표가없는 *를 포함하지 않습니다. if 문 ('IF test THEN closed_stmt ELSE ...')의 구문에는 세미콜론이 포함되지 않습니다. 그러나 IF NOT-facing-north 그 후 turnleft; ELSE'는 세미콜론을 포함하므로 규칙과 일치하지 않습니다. – rici