%{ #include #include #include #include #include #include #define FOREACH_TOKEN(M) \ M(LPAREN) \ M(RPAREN) \ M(LSQUARE) \ M(RSQUARE) \ M(LCURLY) \ M(RCURLY) \ M(APOSTROPHE) \ M(AMPERSAND) \ M(COMMA) \ M(DOT) \ M(EQ) \ M(LT) \ M(PLUS) \ M(MINUS) \ M(MULT) \ M(DIV) \ M(VAR) \ M(IS) \ M(UNLESS) \ M(OTHERWISE) \ M(UNTIL) \ M(DO) \ M(DONE) \ M(PROCEDURE) \ M(FUNCTION) \ M(RETURN) \ M(PRINT) \ M(END) \ M(STRING) \ M(DATE_LITERAL) \ M(INT_LITERAL) \ M(IDENT) \ M(FUNC_IDENT) \ M(PROC_IDENT) %} %locations %define parse.trace %define parse.error verbose %define api.pure full %define lr.type ielr %lex-param {void *scanner} {struct parser *parser} %parse-param {void *scanner} {struct parser* parser} %union { struct ast_node *node; ph_date_t num; int64_t snum; char *str; }; %token STRING %token DATE_LITERAL %token INT_LITERAL %token IDENT; %token FUNC_IDENT; %token PROC_IDENT; %token LPAREN "(" %token RPAREN ")" %token LSQUARE "[" %token RSQUARE "]" %token LCURLY "{" %token RCURLY "}" %token APOSTROPHE "'" %token AMPERSAND "&" %token COMMA "," %token DOT "." %token EQ "=" %token LT "<" %token PLUS "+" %token MINUS "-" %token MULT "*" %token DIV "/" %token VAR "var" %token IS "is" %token UNLESS "unless" %token OTHERWISE "otherwise" %token UNTIL "until" %token DO "do" %token DONE "done" %token PROCEDURE "procedure" %token FUNCTION "function" %token RETURN "return" %token PRINT "print" %token END "end" %{ /** Modifies the signature of yylex to fit our parser better. */ #define YY_DECL int yylex(YYSTYPE *yylval, YYLTYPE *yylloc, \ void *yyscanner, struct parser *parser) /** * Declare yylex. * * @param yylval Bison current value. * @param yylloc Bison location info. * @param yyscanner Flex scanner. * @param parser Current parser state. * @return \c 0 when succesful, \c 1 otherwise. * More info on yylex() can be found in the flex manual. */ YY_DECL; /** * Convert bison location info to our own source location info. * * @param yylloc Bison location info. * @return Internal location info. */ static struct src_loc src_loc(YYLTYPE yylloc); /** * Print parsing error. * Automatically called by bison. * * @param yylloc Location of error. * @param lexer Lexer. * @param parser Parser state. * @param msg Message to print. */ static void yyerror(YYLTYPE *yylloc, void *lexer, struct parser *parser, const char *msg); %} %start input; %% input: /* empty */ %% #include "gen_lexer.inc" static void dump_yychar(struct parser *p, int yychar, YYSTYPE yylval, YYLTYPE yylloc) { struct src_loc loc = src_loc(yylloc); printf("%s:%d:%d: ", p->fname, loc.first_line, loc.first_col); #define PRINT_NAME(token) case token: printf(#token " "); break; switch (yychar) { FOREACH_TOKEN(PRINT_NAME); default: printf("Unknown yychar\n"); return; } char date_str[11] = {0}; switch (yychar) { case INT_LITERAL: printf("(%lld)", (long long int)yylval.snum); break; case IDENT: printf("(%s)", yylval.str); break; case FUNC_IDENT: printf("(%s)", yylval.str); break; case PROC_IDENT: printf("(%s)", yylval.str); break; case DATE_LITERAL: date_to_string(date_str, yylval.num); printf("(%s)", date_str); break; } printf("\n"); } static void dump_lex(struct parser *p) { int yychar; YYSTYPE yylval; YYLTYPE yylloc = {1, 1, 1, 1}; /* run lexer until we reach the end of the file */ while ((yychar = yylex(&yylval, &yylloc, p->lexer, p)) != YYEOF) { dump_yychar(p, yychar, yylval, yylloc); } } static struct src_loc src_loc(YYLTYPE yylloc) { struct src_loc loc; loc.first_line = yylloc.first_line; loc.last_line = yylloc.last_line; loc.first_col = yylloc.first_column; loc.last_col = yylloc.last_column; return loc; } static void yyerror(YYLTYPE *yylloc, void *lexer, struct parser *parser, const char *msg) { (void)lexer; struct src_issue issue; issue.loc = src_loc(*yylloc); issue.fname = parser->fname; issue.buf = parser->buf; src_issue(issue, msg); } struct parser *create_parser() { return calloc(1, sizeof(struct parser)); } void destroy_parser(struct parser *p) { yylex_destroy(p->lexer); free(p); } void parse(struct parser *p, const char *fname, const char *buf) { p->fname = fname; p->buf = buf; p->comment_nesting = 0; p->failed = false; yylex_init(&p->lexer); yy_scan_string(buf, p->lexer); // debugging, remember to reset yy_scan_string once the actual parser // runs dump_lex(p); // yyparse(p->lexer, p); }