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.
This is not a lex/yacc problem.
The function dealWithDocPropertyErrors()
calls the C library function exit()
, which terminates the process, and never returns.