간단한 서식 언어 용 컴파일러를 만들려고합니다.하지만 지금은 인쇄하고 싶습니다. 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;
}