2016-12-30 20 views
2

Flex와 Bison을 사용하여 간단한 형식 지정 언어 용 컴파일러를 작성하려고합니다. 나는 아직 시작 단계에 있으며 일부 기능을 코딩했습니다.Bison (Yacc)이 이유없이 새로운 줄을 인쇄하는 이유는 무엇입니까?

아직이 단계에서는 어디에도 yyout을 인쇄하지 않았습니다. 출력 파일에 무언가가 인쇄되는 오류 케이스가 있는데,이 입력에서는 분명히 발생하지 않습니다. 다른 모든 인쇄 명령문은 콘솔에 인쇄됩니다. 그래서 출력 파일이 완전히 비어있을 것으로 예상됩니다.

\begin {document} 

\tabsize(5) 
\title{"Why I Love Compiler Design"} 
\author{"COMP421 Student"} 
\date{29/12/2016} 
\pagesetup{30,100 } 

\end{document} 

생성 된 출력 파일은 다음과 같습니다 : 9 개 빈 줄이 있습니다

enter image description here

, 내가에 있던 9 개 라인에 해당하는 그러나, 나는 내 입력 파일로 다음을 사용하려고 내 입력 파일. 그러나 예상 한 결과는 빈 줄 하나뿐입니다.

이 내 .L 파일입니다

%{ 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    #include "y.tab.h" 
    void yyerror(const char *); 
    int yylex(void); 

    /* "Connect" with the output file */ 
    extern FILE *yyout; 
    extern int yylineno; 

    /* An array with counters of how many times each of the 5 document properties appears in the input file. The order of the properties is defined in the enum below */ 
    int docPropertyCounters[5]; 

    /* An enumerated list with the 5 document properties */ 
    typedef enum {PAGE_SETUP, TAB_SIZE, DOC_TITLE, DOC_AUTHOR, DOC_DATE} document_property; 

    /* Takes an integer and returns the corresponding document property as a string. The order is based on the enum. */ 
    static inline char *stringFromDocPropertyEnum(document_property indexOfProperty) { 
     static char *strings[] = { "\\pagesetup{}", "\\tabsize()", "\\title{}", "\\author{}", "\\date{}"}; 
     return strings[indexOfProperty]; 
    } 
%} 

%union { 
    int iValue;  /* integer value */ 
    char* sValue;  /* C-String */ 
}; 

%start file /* defining the start condition */ 

%token BSLASH LBRACE RBRACE LPAREN RPAREN COMMA 

%token BEGIN_ END DOCUMENT /* BEGIN seems to be a reserved word so BEGIN_ was used instead */ 

%token PAGESETUP TABSIZE TITLE AUTHOR DATE 

%token <iValue> INTEGER 

%token <sValue> DDMMYYYYDATE STRING 

%% 

file: beginDocument docProperties endDocument 
      { 
       /* Checks for all possible errors in document properties */ 
       for (int i = 0; i < sizeof(docPropertyCounters)/sizeof(docPropertyCounters[0]); i++) 
        if (docPropertyCounters[i] < 1) 
         /* yyerror() is not used in this function because the line number does not need to be shown */ 
         fprintf(stderr, "SYNTAX ERROR: Your source file does not contain the required document property %s", stringFromDocPropertyEnum(i)); 
        else if (docPropertyCounters[i] > 1) 
         fprintf(stderr, "SYNTAX ERROR: Your source file contains more than one instance of the document property %s", stringFromDocPropertyEnum(i)); 
      } 
      | /* An empty document is parsed to an empty document, no errors generated*/ 
      ; 

beginDocument: BSLASH BEGIN_ LBRACE DOCUMENT RBRACE; 

docProperties: docProperties docProperty 
       | /* empty */ 
       ;     

    /* required properties... there should be one instance of each in the input file */ 
docProperty: pageSetupProperty { docPropertyCounters[PAGE_SETUP]++; } 
       | tabSizeProperty { docPropertyCounters[TAB_SIZE]++; } 
       | titleProperty { docPropertyCounters[DOC_TITLE]++; } 
       | authorProperty { docPropertyCounters[DOC_AUTHOR]++; } 
       | dateProperty { docPropertyCounters[DOC_DATE]++; } 
       ; 

pageSetupProperty: BSLASH PAGESETUP LBRACE INTEGER COMMA INTEGER RBRACE; 

tabSizeProperty: BSLASH TABSIZE LPAREN INTEGER RPAREN; 

titleProperty: BSLASH TITLE LBRACE STRING RBRACE; 

authorProperty: BSLASH AUTHOR LBRACE STRING RBRACE; 

dateProperty: BSLASH DATE LBRACE DDMMYYYYDATE RBRACE; 

endDocument: BSLASH END LBRACE DOCUMENT RBRACE; 

%% 

int yywrap(void) { 
    return 1; 
} 

void yyerror(const char* str) 
{ 
    fprintf(stderr,"SYNTAX ERROR near line [%d]: %s\n",yylineno, str); 
} 

PS : 나는 윈도우 10와 플렉스의 아주 오래된 버전을 사용하고 있습니다 (2.5.4a이 내 .Y 파일

%{ 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    #include "y.tab.h" 
    void yyerror(const char *); 
    int yylex(void); 
    /* "Connect" with the output file */ 
    extern FILE *yyout; 
    extern int yyparse(); 
%} 

/* Allows printing the line number (of an error) */ 
%option yylineno 

%% 

^\\ { printf("LEX returned token BSLASH\n"); return BSLASH; } /* every backslash has to be at the start of a line */ 
\{ { printf("LEX returned token LBRACE\n"); return LBRACE; } 
\} { printf("LEX returned token RBRACE\n"); return RBRACE; } 
\( { printf("LEX returned token LPAREN\n"); return LPAREN; } 
\) { printf("LEX returned token RPAREN\n"); return RPAREN; } 
, { printf("LEX returned token COMMA\n"); return COMMA; } 

begin { printf("LEX returned token BEGIN_\n"); return BEGIN_; } /* Note the use of \ in this and other regex expressions to escape the following symbols: \, {, }, (,), */ 
end  { printf("LEX returned token END\n"); return END; } 
document { printf("LEX returned token DOCUMENT\n"); return DOCUMENT; } 

pagesetup { printf("LEX returned token PAGESETUP\n"); return PAGESETUP; } 
tabsize { printf("LEX returned token TABSIZE\n"); return TABSIZE; } 
title  { printf("LEX returned token TITLE\n"); return TITLE; } 
author { printf("LEX returned token AUTHOR\n"); return AUTHOR; } 
date  { printf("LEX returned token DATE\n"); return DATE; } 

(((0[1-9]|[12][0-9]|30)[-/ ]?(0[13-9]|1[012])|31[-/ ]?(0[13578]|1[02])|(0[1-9]|1[0-9]|2[0-8])[-/ ]?02)[-/ ]?[0-9]{4}|29[-/ ]?02[-/ ]?([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00)) { printf("LEX returned token DDMMYYYYDATE\n"); yylval.sValue = yytext; return DDMMYYYYDATE; } 
[0-9]*[1-9][0-9]* { printf("LEX returned token INTEGER\n"); yylval.iValue = atoi(yytext); return INTEGER; } 
\".*\"    { printf("LEX returned token STRING\n"); yylval.sValue = yytext; return STRING; } 

    /* skip whitespace which is not part of a string */ 
[ \t] ; 

    /* anything else is an error */ 
. yyerror("invalid character"); 

%% 

int main(int argc, char *argv[]) { 
    if (argc != 3) 
     yyerror("ERROR You need 2 args: inputFileName outputFileName"); 
    else { 
     yyin = fopen(argv[1], "r"); 
     yyout = fopen(argv[2], "w"); 
     yyparse(); 
     fclose(yyin); 
     fclose(yyout); 
    } 

    return 0; 
} 

입니다

).

+1

그것은하지 않습니다 .... 코드에 내 제안을 테스트하지 않았습니다. 이것은 당신이 사용하고있는 * lex * 또는 * flex *에 의해 수행됩니다. – EJP

답변

2

공백 패턴에 넣지 않았기 때문에이 줄에는 캐리지 리턴 및/또는 줄 바꿈 \r\n이 포함되어 있습니다.

은 아마 당신은이 있어야합니다

[ \t\r\n]  ; 

당신은 또한 사양에 C 스타일의 주석을 사용하는 방법에 대해주의해야합니다. 때때로 이들은 패턴으로 취급됩니다. 나는 항상 학생들에게 실제 C 코드에 스타일 주석만을 넣도록 조언합니다. 예를 들어 다음을 수행하는 것이 더 좋습니다.

[ \t\r\n]  ; /* skip whitespace which is not part of a string */ 

다른 곳에서는 의견을 입력하지 마십시오. 다른 사람들은 동의하지 않을 수도 있지만 flex와 bison에서 많은 비탄을 피할 수 있습니다.

PS : 나는

+0

난 그냥 제안을 테스트하고 그것은 매력처럼 작동합니다 – hb20007

+1

성능상의 이유로 여기에'[\ t \ r \ n] +'을 선호합니다. 생성 된 switch 문을 한 번만 실행합니다. – EJP

+1

C 주석을 플리츠 파일에 넣는 것은 아무런 문제가 없습니다 * 그것을 들여 쓰기하는 것은 * Posix에서 필요하며 모든 lex 구현에서 작동한다고 생각합니다. Flex는 때로는 들여 쓰기가없는 주석을 없애기도하지만, 나는 피하는 것이 좋습니다. 나는 또한이 질문에 이르게 한 오류를 잡을'% option nodefault '를 강력히 추천한다. – rici