2017-01-02 17 views
-1

간단한 서식 언어 용 컴파일러를 만들려고합니다.하지만 지금은 인쇄하고 싶습니다. Bison이 인식 할 때 출력 파일에 대한 메시지Flex/Bison (Lex/Yacc)을 사용하여 2 줄의 순서를 변경하면 출력 파일로 인쇄되지 않습니다

beginDocument docProperties endDocument 

먼저 기능이 예상대로 작동하는 .y 파일을 보여줍니다. 그런데, 나는 단지 2 줄의 코드 순서를 변경하고 더 이상 출력 파일에 인쇄하지 않을 것이다!

Message 

정확히 :

\begin {document} 

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

\end{document} 

내가이 출력을 얻을, 입력 파일로이와

%{ 
    #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; 

    /* Integers related to user-defined document properties */ 
    int tabSize, linesPerPage, charsPerLine, linesPrinted, pageNumber = 1; 

    char* title; /* char* title, author, date; is wrong. In C that would have been char *title, *author, *date because typically in C it's int *p while in C++ it's int* p */ 
    char* author; 
    char* date; 

    /* 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 a document_property enum (basically an integer) and returns the corresponding document property as a string. The order is based on the enum. */ 
    static inline char *stringFromDocPropertyEnum(const document_property indexOfProperty) { 
     static char *strings[] = { "\\pagesetup{}", "\\tabsize()", "\\title{}", "\\author{}", "\\date{}"}; 
     return strings[indexOfProperty]; 
    } 

    /* Checks for all possible errors in document properties */ 
    void dealWithDocPropertyErrors() { 
     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)); 
     } 
     exit(-1); 
    } 

    /* Returns the string it takes as an argument excluding the first and last characters */ 
    char* removeFirstAndLastChar(char* string) { 
     string = string + 1; // Removes the first character 
     int i = 0; 
     for (; string[i] != '\0'; i++); 
     string[i - 1] = '\0'; 
     return string; 
    } 
%} 

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

%error-verbose /* sometimes provides better error reporting. Useful sometimes when debugging */ 

%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 
      { 
       fprintf(yyout, "Message"); 
       dealWithDocPropertyErrors(); 
      } 
      | /* 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 
        { 
         linesPerPage = $4; 
         charsPerLine = $6; 
        } 
        ; 

tabSizeProperty: BSLASH TABSIZE LPAREN INTEGER RPAREN 
       { 
        tabSize = $4; 
       } 
       ; 

titleProperty: BSLASH TITLE LBRACE STRING RBRACE 
       { 
        /* $4 is copied into title excluding the quotation marks at the beginning and end of the string */ 
        title = removeFirstAndLastChar($4); /* $4 is a "pseudo-variable" and can be passed in like this */ 
       } 
       ; 

authorProperty: BSLASH AUTHOR LBRACE STRING RBRACE 
       { 
        author = removeFirstAndLastChar($4); 
       } 
       ; 

dateProperty: BSLASH DATE LBRACE DDMMYYYYDATE RBRACE 
       { 
        date = removeFirstAndLastChar($4); 
       } 
       ; 

endDocument: BSLASH END LBRACE DOCUMENT RBRACE 
      { 
       // Freeing memory created by strdup() 
       free(title); 
       free(author); 
       free(date); 
      } 
      ; 
%% 

int yywrap(void) { 
    return 1; 
} 

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

:

이 잘 작동 .Y 파일입니다 내가 기대하는 것. 내가 문서 속성 오류를 처리 한 후 메시지를 인쇄 할 것을 가정

, 나는 내가 할 수있는 메시지와 그 후 하나를 출력 라인의 순서를 변경 그것을 :

dealWithDocPropertyErrors(); 
fprintf(yyout, "Message"); 

이제 동일한 입력에 대해 빈 출력 파일을 얻습니다. 컴파일 중 경고/오류가 표시되지 않습니다.

Windows 10 및 Flex 2.5.4a를 사용하고 있습니다. 내 .l 파일이 아래와 같습니다.

%{ 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    #include "y.tab.h" 
    void yyerror(const char *); 
    int yylex(void); 
    extern FILE *yyout; /* "Connect" with the output file */ 
    extern int yyparse(); 
%} 
/* %option noyywrap;  Tells flex not to declare the function yywrap() which is only useful in the case of more than 1 input file */ 
    /* Allows printing the line number (of an error) */ 
%option yylineno 
    /* Catches some errors */ 
%option nodefault 
    /* Tells flex not to generate code for the input() and unput() functions which I will not be using */ 
%option nounput 
%option noinput 
    /* Prints the tokens flex recognizes to the console. Useful when debugging and avoids having to write printf() statements for that */ 
%option debug 

%% 

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

begin { return BEGIN_; } 
end  { return END; } 
document { return DOCUMENT; } 

pagesetup { return PAGESETUP; } 
tabsize { return TABSIZE; } 
title  { return TITLE; } 
author { return AUTHOR; } 
date  { 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)) { yylval.sValue = strdup(yytext); return DDMMYYYYDATE; } 
[0-9]*[1-9][0-9]* { yylval.iValue = atoi(strdup(yytext)); return INTEGER; } /* strdup() is string duplicate. yytext must be copied because of its temporary nature */ 
\".*\"    { yylval.sValue = strdup(yytext); return STRING; } 

    /* skip whitespace which is not part of a string. [ \t\r\n]+ is better than [ \t\r\n] performance-wise */ 
[ \t\r\n]+ ; 

    /* 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; 
} 

답변

4

이것은 렉스/yacc 문제가 아닙니다.

함수 dealWithDocPropertyErrors()은 프로세스를 종료하고 반환하지 않는 C 라이브러리 함수 exit()을 호출합니다.