2014-10-06 7 views
2

yacc 파서에서 오류를 추적하는 방법에 대해서는 알지 못합니다. 우리는 lex 파일에 yylineno을 사용하려하고 %option yylineno을 추가하려고 시도했지만 여전히 작동하지 않습니다. 우리는 yacc에서 이러한 변수에 액세스 할 수 없습니다.yacc 파서를 사용하여 오류 행 번호를 감지하는 방법

줄 번호와 함께 yacc에 error을 사용하여 구문 오류를 인쇄하면됩니다.

여기 여기 지금 우리 .l 파일

%{ 
#include <stdio.h> 
#include <stdlib.h> 
#include "y.tab.h" 
int yylineno=1; 

%} 

%option yylineno 

identifier [a-zA-Z_][a-zA-Z0-9_]* 
int_constant [0-9]+ 
delimiter  ; 

%% 

"int"  {return INT;} 
{int_constant} return INT_CONST; 
{identifier} return IDENT; 
\=  {return ASOP;} 
\+  {return PLUS;} 
\-  {return MINUS;} 
\*  {return MULT;} 
\/  {return DIV;} 
\,  {return COMMA;} 
\(  {return OP;} /*OP CP = Opening Closing Parenthesis*/ 
\)  {return CP;} 
\[  {return OB;} /*OB CB = Opening Closing Brace*/ 
\]  {return CB;} 
\{  {return OCB;} /*OCB CCB = Opening Closing Curly Brace*/ 
\}  {return CCB;} 
{delimiter} return DEL; 
[ \t] 
[\n]  {yylineno++;} 


%% 

의 해당 파일에 문제의 숫자가 우리의 .y 파일

%{ 
#include <stdio.h> 
#include <string.h> 
#include "y.tab.h" 

extern FILE *yyin; 

%} 

%token INT INT_CONST IDENT ASOP PLUS MINUS MULT DIV DEL COMMA CP CB CCB 
%left OP OB OCB 


%% 

program:  program_unit; 
program_unit: program_unit component | component 
component: var_decl DEL | func_decl DEL | func_defn ; 
var_decl:  dt list; 
dt:  INT; 
list:  list COMMA var | var 
     | error {printf("before ';' token\n"); yyerrok;} 
     | error INT_CONST {printf("before numeric constant\n"); yyerrok;}; 
var:  IDENT 
     |IDENT init; 
init:  ASOP IDENT init | ASOP expr | ASOP IDENT ; 
expr:  IDENT op expr | const op expr | const | OP expr CP; 
const:  INT_CONST; 
op:  PLUS | MINUS | MULT | DIV; 
func_decl: dt mult_func; 
mult_func: mult_func COMMA mfunc | sfunc; 
mfunc:  IDENT OP CP; 
sfunc:  IDENT OP CP OCB func_body CCB; 
func_body: program_unit; 

func_defn: dt IDENT OP CP OCB func_body CCB 
     | IDENT OP CP OCB func_body CCB; 

%% 

int yyerror(char *s){ 
    extern int yylineno; 
    fprintf(stderr,"At line %d %s ",s,yylineno); 
} 

int yywrap(){ 
    return 1; 
} 

int main(int argc, char *argv[]){ 
    yyin=fopen("test.c","r"); 
    yyparse(); 
    fclose(yyin); 
    return 0; 
} 
+1

시도한 것을 보여주십시오. 그렇지 않으면 우리는 당신이 잘못한 것을 말할 수 없습니다. –

+0

@Stephen C. Mister, 우리의'.l'과'.y' 파일은 최근 포스트와 함께 있습니다. 당신은 또한 우리에게 예제를 줄 수 있습니다, evan은 가장 단순한 것입니다. 고맙습니다. – Jin

답변

4

하지만 그들 중 누구도 당신의 들소에게 제공되는 것을 yylineno을 방지하지 않습니다 생성 된 파서.

yyerror의 정의로 인해 컴파일 타임 경고가 표시됩니다. 또는 여러 가지 경고가 표시 될 수 있습니다.

첫째, 올바른 서명은 다음과 같습니다

void yyerror(const char *msg); 

그것은이 int을 반환 괜찮아요하지만 값이 사용되지 않습니다; 그러나 함수의 정의가 끝나지 않으므로 컴파일러는 값이 반환되지 않는다는 사실에 대해 불평 할 것입니다. 또한 yyerror은 일반적으로 리터럴 문자열 인수와 함께 불려지지만 변경할 수 없습니다. 표준 C를 사용하면 리터럴 문자열을 매개 변수 유형이 const가 아닌 함수로 전달할 수 있지만 사용법은 권장되지 않으며 컴파일러에서 경고 할 수 있습니다. 더욱 중요한

fprintf(stderr,"At line %d %s ",s,yylineno); 

s%d (정수) 형식 (문자열)과 yylineno (정수)로 %s (문자열) 형식을 적용한다; 다시 말하지만 컴파일 타임 경고가 나타나야하며 오류를 무시하면 프로그램이 중단됩니다. (yylineno 관련) 마지막으로

다음 플렉스 생성 된 스캐너가 정의하고 yylineno를 초기화하고 당신을 위해 계산을 (당신이 줄 번호를 계산하려면 좋은 생각입니다) 당신은 당신의 flex 입력에 %option yylineno을 지정하는 경우 . 따라서 .l 파일에 yylineno을 정의하면 컴파일시 오류가 발생합니다 (재정의가 yylineno). 또한 yylineno ( [\n] {++yylineno;})을 명시 적으로 증가 시키면 중복 계산이 끝납니다. yylineno은 스캐너에 의해 증가 된 다음 사용자 작업에 의해 다시 증가합니다. 조언 : %option yylineno을 지정하고 flex로 모든 것을 처리하도록하십시오. bison 파일에 extern으로 신고하기 만하면됩니다. 무시 된 공백 문자 목록에 \n을 추가하면됩니다.

하나는주의 : bison에 직접 yylineno를 사용하여이 bison -generated 파서가 하나 내다 토큰을 읽을 보통 때문에 당신이 구문 오류에 대한 정확한 위치를하지 않으며, yylineno 이미에서 줄 번호에 업데이트 된 것을 의미합니다 이 토큰의 끝 부분 인 bison은 구문 오류를 감지합니다. 때로는 누락 된 토큰으로 인해 구문 오류가 발생하는 경우가 있습니다.

일부 다른 문제 :

  • 그것은 훨씬 더 스타일 (IMHO)의 리터럴 문자가 bison에서 토큰 이름을 정의하고 flex 파일을 조정하기보다는 토큰을 사용할 수 있습니다. 리터럴 문자 만 사용하면 두 파일이 서로 동기화되는 것이 훨씬 쉽습니다. 문법은 읽기 쉽습니다. 당신은 단지 문법에 ')'를 사용하는 대신

    /*OP CP = Opening Closing Parenthesis*/ 
    

    같은 의견을 필요로하지 않으며, 렉서에서이 같은 수행 할 수 있습니다

    [][=+*/,(){}-] { return yytext[0]; } 
    

    을 또는 당신도 그냥 기본값을 사용할 수 있습니다 마지막에 규칙 :

    . { return yytext[0]; } 
    
  • 위의 관련, 그리고 보통 두 번째 옵션 (기본 규칙)을 선택하는 이유는, 당신의 렉서는 모든 possi에 대한 규칙이없는 결과적으로 굴곡 제공 기본 규칙이 사용됩니다. 플렉스 제공 기본 규칙은 유효하지 않은 문자를 yyout에 에코로 보내는 것입니다. 이것은 실제 컴파일러에서 결코 원하는 것이 아니므로 입력 오류 (또는 스캐너 버그)가 자동으로 숨겨집니다. 위에서 제안한 것과 같은 기본 규칙을 사용하고 플렉스 생성 기본 규칙을 피하기 위해 %option nodefault을 사용하여 자신을 보호하는 것이 좋습니다. %option nodefault을 사용하면 입력이 일치하지 않을 가능성이있는 경우 flex가 경고를 표시합니다. 이 경고를 무시하지 마십시오.