2013-09-25 1 views
1

입력 코드에서 발생하는 구문 오류의 번호를 내 코드가 인쇄하도록하십시오. 내 코드는 다음과 같습니다.bison-flex에서 구문 오류를 계산하는 방법

%{ 
#include <stdio.h> 
#include <math.h> 
void yyerror(char *); 
extern int yylval; 
extern FILE *yyin; 
extern FILE *yyout; 
extern yylineno; 
extern int yyparse(void); 
extern int yylex(void); 
extern int yywrap() { return 1; } 
extern char* yytext; 
int errors; 
%} 

%debug 
%start m_class 


%token IF ELSE INT CHAR CLASS NEW GURISE VOID WHILE 
%token PUBLIC PROTECTED PRIVATE STATIC FINAL ABSTRACT 
%token PLUS MINUS MUL DIV MODULO 
%token EQ NEQ GRT LT GREQ LEQ 
%token OR AND NOT 
%token AR_PAR DEK_PAR AR_AGK DEK_AGK AR_STRO DEK_STRO 
%token SEMICOLON ANATHESI COMA 
%token MY_INT SINT MY_CHAR ID 

%right   ANATHESI 
%left   OR AND 
%nonassoc  EQ NEQ GRT LT GREQ LEQ 
%left   PLUS MINUS MUL DIV MODULO 
%right   NOT 
%right   "then" ELSE 

%% 

m_class: m_class class_declaration 
     | class_declaration 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

class_declaration: CLASS ID class_body 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

class_body: AR_STRO variable_declaration constructor method_declaration DEK_STRO 
     | error "\n" {yyerrok; errors++; yyclearin;} 
    ; 

variable_declaration:variable variable_declaration 
     |variable 
     |array_declaration 
     |array_declaration variable_declaration 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

variable: var_type ID SEMICOLON 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

var_type: INT 
     |CHAR 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

array_declaration: ID ANATHESI NEW var_type AR_AGK MY_INT DEK_AGK SEMICOLON 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 


constructor: modifier ID AR_STRO variable_declaration DEK_STRO 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

modifier: PUBLIC 
     | PROTECTED 
     | PRIVATE 
     | STATIC 
     | FINAL 
     | ABSTRACT 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 
method_declaration: modifier meth_type ID parameters meth_body 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

meth_type: VOID 
     | var_type 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

parameters: AR_PAR par_body DEK_PAR 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

par_body: var_type ID 
     | par_body COMA var_type ID 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

meth_body: AR_STRO bodybuilder DEK_STRO 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

bodybuilder: statement GURISE expression SEMICOLON 
     |statement bodybuilder 
     |statement 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

statement: anathesh 
     | if_statement 
     | while_statement 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

anathesh:atath SEMICOLON 
     | atath numeric_expression SEMICOLON 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

atath: ID ANATHESI orisma 
     |ID AR_AGK MY_INT DEK_AGK ANATHESI orisma 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

orisma: ID 
     |MY_INT 
     |SINT 
     |MY_CHAR 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

expression: testing_expression 
     | numeric_expression 
     | logical_expression 
     | ID 
     | MY_INT 
     | SINT 
     | MY_CHAR 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

numeric_expression: expression PLUS expression 
     | expression MINUS expression 
     | expression MUL expression 
     | expression DIV expression 
     | expression MODULO expression 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

testing_expression: expression EQ expression 
     | expression NEQ expression 
     | expression GRT expression 
     | expression LT expression 
     | expression GREQ expression 
     | expression LEQ expression 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 
logical_expression: expression OR expression 
     | expression AND expression 
     | expression NOT expression 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

if_statement: IF sin8iki statement  %prec "then" 
     | IF sin8iki statement ELSE statement 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 


sin8iki: AR_PAR testing_expression DEK_PAR 
     | AR_PAR logical_expression DEK_PAR 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 

while_statement: WHILE sin8iki statement 
     | error "\n" {yyerrok; errors++; yyclearin;} 
     ; 


%% 


void yyerror(char *s) { 
     errors++; 
printf("\n------- ERROR AT LINE #%d.\n\n", yylineno); 
fprintf(stderr, "%d: error: '%s' at '%s', yylval=%u\n", yylineno, s, yytext, yylval); 

} 

int main (int argc, char **argv) { 
     ++argv; 
     --argc; 
     errors=0; 
     if (argc > 0) 
       yyin = fopen (argv[0], "r"); 
     else 
       yyin = stdin; 
     yyout = fopen ("output","w"); 
     yyparse(); 
     if(errors==0) 
       printf("komple"); 
     else 
       printf("la8oi: %d", errors); 
     return 0; 
} 

나는 yyerrok를 수정하려고했지만 그럴 수없는 것 같습니다. 나는 또한 for 루프에 yyparse를 넣으려고했다. 입력 파일에 구문 오류가 5 개 있지만 인쇄는 1 !!!!!! 어떤 아이디어?

+0

환영을 참조하십시오. 태그를 지정할 때주의하십시오. Flex는 Adobe/Apache UI 프레임 워크에 사용됩니다. Flex-Lexer는 어휘 분석기 용으로 사용됩니다. – JeffryHouser

답변

2

생산 :

error "\n" {yyerrok; errors++; yyclearin;} 

아마 당신이 무엇을 기대하지 않습니다.

error 제작물은 일반적인 제작물과 특별히 다르지 않습니다. 가장 큰 차이점은 error 프로덕션이 다음과 같은 토큰 (일반적으로 터미널)과 동기화된다는 것입니다. [1] bison의 경우 큰 따옴표로 묶인 문자열 ("foo")은 유효한 터미널이지만 해당 토큰 번호를 쉽게 얻을 수 없으므로 렉서에게는 어려움이 있습니다. [2] 이것은 작은 따옴표로 묶인 문자열 ('a')과는 다르며, 한 문자 여야하며 숫자가 단일 문자에 해당하는 정수인 토큰을 나타냅니다. 이것은 작은 따옴표와 큰 따옴표 사이의 C의 차이와 비슷합니다.

따라서 error 프로덕션은 토큰 번호가 'bison'으로 자동 생성되는 ''\ n ' "토큰과 동기화를 시도합니다. 그러나 당신의 렉서가이 토큰 번호를 생성하는 것은 거의 불가능합니다. 왜냐하면 먼저 번호가 무엇인지 알지 못하기 때문이며, 두 번째 이유는 렉서가 공백을 무시한다고 의심하기 때문입니다. [3] 렉서를 보지 않고도 말하기는 어렵지만, 합리적인 가정처럼 보입니다.

결과적으로 첫 번째 error 프로덕션은 파일 끝에 도달 할 때까지 토큰을 버립니다.이 시점에서 실패하고 구문 분석이 종료되어 하나의 오류가보고됩니다.


메모.

  1. 보다 정확하게 말해서 미리보기 토큰이 이동 될 수 있습니다. 따라서 나머지 오류 생성으로 생성 된 문자열의 첫 번째 터미널이 될 때까지 토큰을 삭제합니다. 그렇다고 생산량이 줄어들지는 않지만, 아마도 바이슨이 할 수있는 최선의 방법 일 것입니다.

  2. 토큰 이름과 토큰 리터럴을 %token 선언 (또는 선행 선언 중 하나)에 (순서대로) 선언하여 선언 할 수 있습니다. 제 생각에 그것은 "then"으로 무엇을하려는 의도 였지만, 작성한 방식으로는 작동하지 않습니다. 당신이 필요합니다
            %right THEN "then" ELSE
    (또는 그 이상)을 선언 할
            %right THEN "then" ELSE "else"
    은 또한 문법에 "then"과 같이 쓸 수있다 (들소에 의해 생성 된 정수 상수) 상품권 번호 THEN . 분명히 그것은 자동으로 문자열을 인식 할 수 있도록 마술처럼 렉서를 변경하지는 않습니다. 그것은 당신의 책임입니다. 이 형식으로 토큰을 선언 할 때의 주요 이점은 문법을 더 읽기 쉽게 만들어주고 %error-verbose을 사용하면 bison이 더 나은 오류 메시지를 생성 할 수 있다는 것입니다.

  3. 당신의 렉서가 개행 토큰을 반환한다면, 나는 토큰이 '\n' (10 임)으로 반환되기를 기대합니다. 그러나 그것은 좋은 생각입니다. 왜냐하면 문법은 다음과 같은 방식으로 작성되어야하기 때문입니다. 명시 적으로 허용 된 개행 문자. 어떤 언어는 이것을 (예를 들어 파이썬)하지만, 어디에서나 개행 문자가 나타날 수있는 언어에서는 문법이 실제로 복잡해집니다.

0

yyerror() 내에서 카운트하고 자신의 의미 론적 오류에 대해 다른 방법을 호출하십시오.

0

변수 yynerrs에는 지금까지 발생한 구문 오류 수가 포함됩니다. 일반적으로이 변수는 전역 변수입니다. 순수 파서를 요청하면 액션 만 액세스 할 수있는 로컬 변수입니다.

스택 오버플하는 link

관련 문제