diff options
Diffstat (limited to 'src/parser.y')
-rw-r--r-- | src/parser.y | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/src/parser.y b/src/parser.y new file mode 100644 index 0000000..8a4ddb5 --- /dev/null +++ b/src/parser.y @@ -0,0 +1,243 @@ +%{ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#include <posthaste/parser.h> +#include <posthaste/date.h> + +#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 <str> STRING +%token <num> DATE_LITERAL +%token <snum> INT_LITERAL +%token <str> IDENT; +%token <str> FUNC_IDENT; +%token <str> 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); +} |