compiler-constructionbisonflex-lexeryacclex

Printing to output file with Flex/Bison (Lex/Yacc) does not work if I change the order of 2 lines of code


I want to print a message to the output file when Bison recognizes

beginDocument docProperties endDocument

I will first show a .y file where the functionality works just as expected. Then, I will change the order of only 2 lines of code, and printing to the output file no longer works!

This is the .y file that works fine:

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

    extern FILE *yyout;
    extern int  yylineno;

    int tabSize, linesPerPage, charsPerLine, linesPrinted, pageNumber = 1;

    char* title;
    char* author; 
    char* date;

    int docPropertyCounters[5];

    typedef enum {PAGE_SETUP, TAB_SIZE, DOC_TITLE, DOC_AUTHOR, DOC_DATE} document_property;

    static inline char *stringFromDocPropertyEnum(const document_property indexOfProperty) {
        static char *strings[] = { "\\pagesetup{}", "\\tabsize()", "\\title{}", "\\author{}", "\\date{}"};
        return strings[indexOfProperty];
    }

    void dealWithDocPropertyErrors() {
        for (int i = 0; i < sizeof(docPropertyCounters)/sizeof(docPropertyCounters[0]); i++) {
            if (docPropertyCounters[i] < 1) 
                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);
    }

    char* removeFirstAndLastChar(char* string) {
        string = string + 1;
        int i = 0;
        for (; string[i] != '\0'; i++);
        string[i - 1] = '\0';
        return string;
    }
%}

%union { 
    int iValue;
    char* sValue;
}; 

%error-verbose

%start file

%token BSLASH LBRACE RBRACE LPAREN RPAREN COMMA

%token BEGIN_ END DOCUMENT

%token PAGESETUP TABSIZE TITLE AUTHOR DATE

%token <iValue> INTEGER

%token <sValue> DDMMYYYYDATE STRING

%%

file: beginDocument docProperties endDocument
            { 
                fprintf(yyout, "Message");
                dealWithDocPropertyErrors();
            }
          |
          ;

beginDocument: BSLASH BEGIN_ LBRACE DOCUMENT RBRACE;

docProperties: docProperties docProperty
               |
               ;                
    
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
               {
                   title = removeFirstAndLastChar($4);
               }
               ;

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

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

endDocument: BSLASH END LBRACE DOCUMENT RBRACE
             {
                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);
}

With this as the input file,

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

I get this output:

Message

which is exactly what I expect.

Assuming I want to print the message after dealing with document property errors, I change the order of the line that prints the message and the one after it. That is, I make it:

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

I now get an empty output file for the same input.


Solution

  • This is not a lex/yacc problem.

    The function dealWithDocPropertyErrors() calls the C library function exit(), which terminates the process, and never returns.