diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-03-23 16:14:51 +0200 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-03-23 16:14:51 +0200 |
| commit | 5b038666c3e911ffeb78a4d656044e5bd076705b (patch) | |
| tree | 9b09b4f27c39ef6a0139a5eb9bfa5e98a250086c /src/parser_helper.c | |
| parent | 70615379062cdd2e016f5095dfafd23a6dca148c (diff) | |
| download | ek-5b038666c3e911ffeb78a4d656044e5bd076705b.tar.gz ek-5b038666c3e911ffeb78a4d656044e5bd076705b.zip | |
integrate parser work
Diffstat (limited to 'src/parser_helper.c')
| -rw-r--r-- | src/parser_helper.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/parser_helper.c b/src/parser_helper.c new file mode 100644 index 0000000..2501f47 --- /dev/null +++ b/src/parser_helper.c @@ -0,0 +1,125 @@ +#include <stdarg.h> + +#include <cu/parser.h> +#include <cu/debug.h> + +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->buf_offset = 0; + p->comment_nesting = 0; + + p->failed = false; + + yylex_init(&p->lexer); + yy_scan_string(buf, p->lexer); + yyparse(p->lexer, p); +} + +/* I'm not convinced this is foolproof quite yet, more testing would be nice. */ +int next_interesting_feature(YYSTYPE *yylval, YYLTYPE *yylloc, void *scanner, + struct parser *parser) +{ + size_t depth = 0; + while (1) { + int ret = yylex(yylval, yylloc, scanner, parser); + if (ret == LBRACE) { + depth++; + continue; + } + + if (ret == RBRACE && depth > 0) + depth--; + + if (ret == RBRACE && depth == 0) + return 0; + + if (ret == SEMICOLON && depth == 0) + return 0; + + /* return fatal error and parser should abort */ + if (ret == YYEOF) + /* some error for unmatched braces would be cool I think */ + return 1; + } +} + + +struct src_loc to_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; +} + +void yyerror(YYLTYPE *yylloc, void *lexer, struct parser *parser, const char *msg) +{ + (void)lexer; + + struct src_issue issue; + issue.level = SRC_ERROR; + issue.loc = to_src_loc(yylloc); + issue.fctx.fbuf = parser->buf; + issue.fctx.fname = parser->fname; + issue.offset = parser->buf_offset; + src_issue(issue, msg); +} + +long long match_escape(char c) +{ + switch (c) { + case '\'': return '\''; + case '\\': return '\\'; + case 'a': return '\a'; + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + } + + return c; +} + +const char *clone_string(const char *str) +{ + const size_t len = strlen(str) + 1; + char *buf = malloc(len); + if (!buf) { + /* should probably try to handle the error in some way... */ + internal_error("failed allocating buffer for string clone"); + return NULL; + } + + /* skip quotation marks */ + size_t j = 0; + for (size_t i = 1; i < len - 2; ++i) { + char c = str[i]; + + if (c == '\\') + c = match_escape(str[++i]); + + buf[j++] = c; + } + + buf[j] = 0; + return buf; + +} |
