2017-01-08 18 views
1

저는 Lex 및 Bison 파서 생성기를 사용하고 있습니다. 의미론을 정의하는 구문 및 .ypp 파일을 정의하는 .lex 파일이 있습니다.yylineno에서 어떤 줄이 인쇄 될지 어떻게 알 수 있습니까?

Statement : Type ID ASSIGN Exp {check_types_match($1.type, $4.type)} SC 
  • 유형 INT 또는 부울될 수 있습니다 내 .ypp에 나는이 라인을 가지고있다.
  • ID는 식별자입니다.
  • ASSIGN은 = 기호입니다.
  • Exp는 Exp : true이며, 부울로 표현식의 유형을 저장합니다.
  • SC는 ";"입니다.
  • check_types_match는 유형 불일치를 검사하고 오류가있는 경우 해당 행 (yylineno)을 인쇄합니다.

    int x = true 
    ; 
    

    나는 오류가없는 라인 1에 라인이있는 것을 얻을 어떻게 할 수 대신 라인 1에 오류를 인쇄 :이 간단한 입력 파일의

? 당신은 그래서 check_types_match가 호출되는 순간에 온라인 2에 세미콜론을, 도달 할 때까지 오류를 생성하려면

문이 같은 인식되지

답변

1

, yylineno 2.

라인을 가리켜 야합니다 메시지를 다른 줄 번호로 인쇄하려면 어떤 줄을 인쇄할지 결정해야합니다. 여기서 오류는 토큰 int과 토큰 true 사이에 있기 때문에 최소한 두 가지 가능성이 있습니다. 이 경우, 그 모두가 1 행에 있지만, 어떤 프로그램 텍스트가 있었다면 :

int x = 
    true; 

그 토큰 중 하나가 오류를 일으키는 것으로 플래그해야한다는 합리적인 것 같다, 그래서 문제가 파악에 감소 토큰이 표시된 행을 찾아냅니다. 그 토큰은 감축이 일어날 때까지의 고대의 역사이기 때문에 여전히 필요로하는 모든 토큰의 위치를 ​​기억하는 것이 유일한 방법입니다. 이것은 일반적으로 파서 스택에있는 모든 토큰입니다.

다행히도 bison에는이를 수행하는 간단한 방법이 있습니다. 필요한 경우 파서 스택과 평행하게 위치 스택을 유지 한 다음 @1을 참조하여 토큰 1의 위치 개체에 액세스 할 수 있습니다. 심지어 바이슨 파일의 어딘가에 위치 객체에 대한 참조를 사용하는 것만으로도이 정보를 유지하도록 바이슨을 설득하는 것으로 충분합니다. 그래서 당신은 당신의 작업을 변경할 수 있습니다 : (. 당신이이 Exp에 오류를 돌리는 것이 더 적절하다고 생각하는 경우, 또는 @4)

Statement : Type ID ASSIGN Exp {check_types_match($1.type, $4.type, @1)} SC 

을 물론

, 그것은 아주 간단 적이 없다. bison에 모든 수신 토큰의 위치를 ​​알리고 새로 만든 비 종단 용 위치를 만드는 방법을 이해해야합니다 (위의 예에서 Exp 등).)

위치 객체가 여러 행에 걸쳐있을 수있는 토큰 시퀀스의 위치를 ​​참조 할 수 있기 때문에 (비 - 종단의 경우처럼) 위치 객체가 시작과 끝을 모두 나타내는 것은 정상입니다 끝 점. 또한 정확한 오류 메시지를 생성하기 위해 행 번호와 열 오프셋을 모두 사용하는 것이 일반적입니다. N이이다 어디

@$.first_line = @1.first_line; 
@$.first_column = @1.first_column; 
@$.last_line = @N.last_line; 
@$.last_column = @N.last_column; 

같은 것을 쓴 것처럼

typedef struct YYLTYPE { 
    int first_line; 
    int first_column; 
    int last_line; 
    int last_column; 
} YYLTYPE; 

그리고 기본적으로

이 아닌 단말기의 위치 개체가 계산된다 : 따라서, 기본 위치 객체는 다음과 같은 유형이 오른쪽에있는 마지막 문법 기호의 색인. ( bison에는 "문법 기호 수"에 대한 표기가없고 $N 구문의 변수를 사용할 수 없으므로 실제로는 작성할 수 없습니다.)

꽤 잘 당신이 원하는, 들소의 측면에서 아무런 문제가 없습니다. 그러나 당신은 또한 처음에 flex에서 정보를 얻을 필요가 있습니다. 당신이 전역 변수에 의존 flexbison 사이의 간단한 인터페이스를 사용하는 경우

, 현재 토큰을 사용하여 해당 위치의 객체의 이름 (yylval 유사) yylloc입니다. flexyylineno을 자동으로 만들 수 있지만 yylloc에 자동으로 저장하지 않으며 열 번호를 추적하거나 리턴 된 토큰이 두 줄 이상으로 퍼져있는 경우를 처리하는 기본 제공 메커니즘도 없습니다 (이 기능은 문자열 상수 등).

정확한 인프라 정보를 얻는 것은이 질문의 범위를 벗어납니다. 회선 번호 정보 만 요구하기 때문입니다. 당신은 단지 라인 번호를 추적해야하고 여러 줄의 토큰이없는 경우, 모든 플렉스 규칙에 다음을 추가 할 수있는 충분한 것 :

yylloc.first_line = yylloc.last_line = yylineno; 

당신은 멀티 라인 토큰이있는 경우, 당신 에 모든 토큰 액션, 무엇이든 (주석과 공백을)하지 않아도 사람을 추가 할 것

yylloc.first_line = yylloc.last_line; 
yylloc.last_line = yylineno; 

: 대신 다음을 사용할 수 있습니다. 다행히도 flex에는 모든 액션의 시작 부분에 추가되는 매크로가 있으므로 전체 flex 파일을 복잡하게 만들 필요가 없습니다. 그것은 같은 것을 추가 할 수있는 충분한입니다 :

#define YY_USER_ACTION do {    \ 
    yylloc.first_line = yylloc.last_line; \ 
    yylloc.last_line = yylineno;   \ 
} while(0) 

을 (. 당신이 열 번호를 추적 끝날 경우, 너무, 당신은 그것을 수정해야합니다)

또한 yylloc.last_line1으로 초기화되어 있는지 확인해야합니다

; 그렇지 않으면 첫 번째 토큰이 0 행에서 시작됩니다.

자세한 내용은 설명서를 읽어 보시기 바랍니다 : 당신이 재진입/순수 스캐너와 파서를 사용하는 경우

을, 당신은 설명서를 참조해야합니다 위치 객체가 전역없이 전달되는 방법. %bison-locations 선언은 항상 원하는 것은 아닙니다 (재진입/순수 스캐너 및 파서를 사용하지 않는 경우에는 원하는 것은 아닙니다.)

+0

답장을 보내 주셔서 감사합니다! 그것은 나를 도왔습니다 :) 건배! – Loay