1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/* SPDX-License-Identifier: copyleft-next-0.3.1 */
/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */
#include <stdarg.h>
#include <ek/parser.h>
#include <ek/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;
}
|