2017-01-21 6 views
1

나는 들소에서 시프트/줄이기 충돌을 해결하려고합니다. 나는 optional_generics_list과 ctor_arguments 모두 비어있을 수 있음을, 문법옵션 규칙을 추가하려고 할 때 들소에서 시프트/줄이기

new_expr: 
    T_NEW class_name_reference optional_generics_list ctor_arguments 
     { $$ = zend_ast_create(ZEND_AST_NEW, $2, $4, $3); } 
| T_NEW anonymous_class 
     { $$ = $2; } 

optional_generics_list: 
    /* empty */  { $$ = NULL; } 
| generics_list { $$ = $1; } 

ctor_arguments: 
    /* empty */ { $$ = zend_ast_create_list(0, ZEND_AST_ARG_LIST); } 
| argument_list { $$ = $1; } 

문제는 여기에 사실에있다 규칙에 따라 있습니다. optional_generics_list와 ctor_arguments가 모두 비어 있으면 ctor_arguments가 더 높은 우선 순위를 가져야한다고 지정할 수 있습니까? 또는 내 질문이 정확하지 않을 수 있으며 어떻게이 충돌을 대신 해결할 수 있는지.

일부 업데이트 된 정보 : 파일 · 출력 생성의 어쩌면 출력이 도움이 될 것입니다

State 156 conflicts: 1 shift/reduce 

State 156: 

    303 new_expr: "new (T_NEW)" class_name_reference . optional_generics_list ctor_arguments 

    '<' shift, and go to state 304 

    '<'  [reduce using rule 168 (optional_generics_list)] 
    $default reduce using rule 168 (optional_generics_list) 

    optional_generics_list go to state 305 
    generics_list   go to state 306 


State 305 

    303 new_expr: "new (T_NEW)" class_name_reference optional_generics_list . ctor_arguments 

    '(' shift, and go to state 229 

    $default reduce using rule 405 (ctor_arguments) 

    argument_list go to state 546 
    ctor_arguments go to state 552 


State 306 

    169 optional_generics_list: generics_list . 

    $default reduce using rule 169 (optional_generics_list) 
+0

'generics_list'와'argument_list'는 같은 모양입니까? 아니면 더 정확하게 말하면 어느 쪽인가의 시작이 될 수있는 터미널이 있습니까? – rici

+0

또는 빈 목록의 우선 순위가 다른 목록보다 높다는 것은 무엇을 의미합니까? 둘 다 비어 있으면 둘 다 비어 있습니다. – rici

+0

generics_list는 '<'기호로 시작할 수 있지만 ctor_arguments는 '('로 시작합니다. 문제는 빈 규칙입니다. 왜냐하면 ctor_arguments 대신 optional_generics_list 및 argument_list 대신 generics_list를 사용하면 모든 것이 제대로 작동하기 때문입니다. –

답변

0

들소 출력 파일로 표시 문제는 new_expr< 다음 될 수있는 가능성이 있다는 것입니다 generics_list의 일부가 아닙니다. 예를 들어, 문법도 같은 제작 포함 된 경우 그 경우 다음과 같습니다

term: new_expr 
comparison: term '<' term 

(물론, 하나는 실제 문법보다 더 많은 가능성을 가지고 기대를하지만, 사람들은 필수적인 것들입니다. 문법은 두 개의 새로 건설 객체를 비교할 수있는 경우 즉)

, 다음 파서는 보는 <new_exprgenerics_list의 시작, 또는 간단한 비교 연산자인지 말할 수 없다 generics_listctor_arguments이 모두 생략 된 경우 :

if new Foo < oldFoo then... 

myFoo = new Foo<int>(42) 

간단한 수정은 표현에 사용되는 것입니다 경우 new_expr가 괄호로 주장하는 것입니다.

C++에서는 이름이 템플릿인지 여부를 알기 때문에이를 처리합니다. 이름에서 템플릿 인수를 사용할 수있는 경우 이름 뒤에 오는 <은 템플릿 인수 목록 시작으로 해석됩니다. 그렇지 않은 경우에는 작음 연산자입니다. 따라서 v이 템플릿 화 된 경우 (new v) < ...을 작성해야하지만 v이 단순한 typename 인 경우 괄호를 생략 할 수 있습니다 : new int < .... 그것을 구현하는 것은 까다 롭습니다. 어떤 종류의 어휘 피드백이 필요하고 템플릿 선언을 어디에 둘 수 있는지에 대해 몇 가지 제한을 가할 필요가 있습니다. C++에는 비슷한 해상도의 파싱 문제가 있습니다. 예를 들어 new int * i*new 표현식의 형식이 형식으로 구문 분석 할 수있는 가장 긴 시퀀스 인 것으로 나타내는 규칙을 사용하여 포인터 형식 수정 자로 구문 분석되기 때문에 오류입니다.

new을 연산자의 왼쪽 인수로 사용하면 필수 괄호로 사용합니다. 독자에게는 혼동이 덜하기 때문에. 문법은 구문 분석을 단순화하는 것이기 때문에 문법을 단순화합니다. 언어의 문서화에 필수적인 부분이며, 불필요하게 복잡한 문법은 언어를 불필요하게 배우고 이해하기 어렵게 만듭니다.

흥미롭게도 C++에 관한 위의 노트를 작성하는 과정에서 한 가지 주요 C++ 컴파일러의 파서에서 버그를 발견했습니다. (적어도 어떤 컴파일러가 버그인지 알 것 같습니다. 두 개의 인기있는 컴파일러가 일관성없는 동작을한다는 것을 발견했다고 말하는 것이 더 정확할 수 있습니다. 따라서 그 중 하나가 틀렸어 야합니다.) 더 단순한 규칙은 어떤 부작용이없는 프로그램에도 아무런 영향을 끼치 지 않았을 것이고, 버그를 훨씬 덜 가능성있게 만들었을 것이다. 따라서 표현식의 중간에 괄호 안의 숫자가없는 new 연산을 허용하는 것이 부가가치라는 것은 나에게 분명하지 않습니다.

+0

실제로 확인했습니다. 사실, new_expr은 비교 표현식의 일부가 될 수 있습니다. 고마워. –