-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpp_macro_expander.cbrt
More file actions
307 lines (276 loc) · 12.6 KB
/
pp_macro_expander.cbrt
File metadata and controls
307 lines (276 loc) · 12.6 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/* Copyright 2020-2024 Kinglet B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef STDLIB_H_INCLUDED
#define STDLIB_H_INCLUDED
#include <stdlib.h>
#endif
#ifndef STDINT_H_INCLUDED
#define STDINT_H_INCLUDED
#include <stdint.h>
#endif
#ifndef PP_H_INCLUDED
#define PP_H_INCLUDED
#include "pp.h"
#endif
#ifndef PP_TOKENS_H_INCLUDED
#define PP_TOKENS_H_INCLUDED
#include "pp_tokens.h"
#endif
%grammar%
%prefix ppme_
%params struct preprocessor *pp, struct pptk **pp_input_chain, int is_final, struct pptk **pp_output_chain, int keep_defined
%on_next_token \
if (*pp_input_chain) { \
sym = g_pptk_to_ppme_[(*pp_input_chain)->tok_]; \
if ((!keep_defined) && (sym == PPME_DEFINED)) { \
sym = PPME_IDENT; \
} \
if (sym == PPME_IDENT) { \
struct macro *m = NULL; \
m = mt_find(&pp->macro_table_, (*pp_input_chain)->text_, (*pp_input_chain)->text_len_); \
if (m && !m->nested_invocation_) { \
if (m->is_function_style_) { \
sym = PPME_FUNCTION; \
} \
else { \
sym = PPME_OBJECT; \
} \
} \
} \
} \
else { \
if (!is_final) return _PPME_FEED_ME; \
sym = PPME_INPUT_END; \
}
%token IDENT OBJECT FUNCTION DEFINED PAR_OPEN PAR_CLOSE COMMA WS_TOK OTHER
%token_type struct pptk *
%constructor $$ = NULL;
%move $$ = $0; $0 = NULL;
%destructor pptk_free($$);
%token_action $$ = pptk_pop_front(pp_input_chain);
%nt opt-function-seq
%type OBJECT FUNCTION: struct { struct pptk *tk_; struct macro *m_; }
%constructor $$.tk_ = NULL; $$.m_ = NULL;
%move $$.tk_ = $0.tk_; $$.m_ = $0.m_;
%destructor pptk_free($$.tk_); macro_free($$.m_); /* Reduction of OBJECT drops a reference and might free the macro */
%token_action \
$$.tk_ = pptk_pop_front(pp_input_chain); \
struct macro *m = mt_find(&pp->macro_table_, $$.tk_->text_, $$.tk_->text_len_); \
if (!m) { \
/* In-between %on_next_token and actually shifting the same token, we lost the macro.
* This should never happen as the only thing happening between %on_next_token and
* %token_action are reductions in the current grammar (e.g. no #undef can be processed,)
* cannot recover */ \
dx_printf(pp->dx_, "Internal error, lost macro definition\n"); \
return _PPME_INTERNAL_ERROR; \
} \
m->refcount_++; \
$$.m_ = m;
%nt top-stream total
%nt non-function ws-opt ws-opt-emit par-span arg
%type non-function ws-opt par-span arg: struct pptk *
%constructor $$ = NULL;
%move $$ = $0; $0 = NULL;
%destructor pptk_free($$);
%nt args
%type args: struct macro_arg_inst *
%constructor $$ = NULL;
%move $$ = $0; $0 = NULL;
%destructor macro_arg_inst_free($$);
total: top-stream opt-function-seq;
top-stream: ;
top-stream: top-stream opt-function-seq IDENT {
*pp_output_chain = pptk_join(*pp_output_chain, $2);
$2 = NULL;
}
top-stream: top-stream opt-function-seq COMMA {
*pp_output_chain = pptk_join(*pp_output_chain, $2);
$2 = NULL;
}
top-stream: top-stream ws-opt-emit PAR_OPEN {
*pp_output_chain = pptk_join(*pp_output_chain, $2);
$2 = NULL;
}
top-stream: top-stream opt-function-seq PAR_CLOSE {
*pp_output_chain = pptk_join(*pp_output_chain, $2);
$2 = NULL;
}
top-stream: top-stream opt-function-seq OTHER {
*pp_output_chain = pptk_join(*pp_output_chain, $2);
$2 = NULL;
}
top-stream: top-stream opt-function-seq FUNCTION ws-opt PAR_OPEN args PAR_CLOSE {
/* Insert FUNCTION expansion */
int r = macro_expand(pp, $2.tk_, $2.m_, $5, pp_output_chain);
if (r) {
return _PPME_INTERNAL_ERROR;
}
}
top-stream: top-stream opt-function-seq OBJECT {
/* Insert OBJECT expansion */
int r = macro_expand(pp, $2.tk_, $2.m_, NULL, pp_output_chain);
if (r) {
return _PPME_INTERNAL_ERROR;
}
}
/* Insert "DEFINED (ID)" and "DEFINED ID" expansions; this gets a little bit clumsy because
* prior to the parser, the IDENT may already have been translated to a FUNCTION or an OBJECT
* token (see %next_token for instance); so we need to accept all three as an argument to
* DEFINED, without expanding anything. The actual expansion check is performed in pp_const_expr.cbrt,
* if preservation is desired. Goal here is to adhere to C99 6.10.1-3 in particular: "(except
* for those macro names modified by the defined unary operator)". */
top-stream: top-stream opt-function-seq DEFINED ws-opt PAR_OPEN ws-opt IDENT ws-opt PAR_CLOSE {
/* Insert "DEFINED (ID)" expansion; this is a straight up copy to preserve it for
* preprocessor constant expression evaluation. */
*pp_output_chain = pptk_join(*pp_output_chain, $2); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $3); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $4); /* PAR_OPEN */
*pp_output_chain = pptk_join(*pp_output_chain, $5); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $6); /* IDENT */
*pp_output_chain = pptk_join(*pp_output_chain, $7); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $8); /* PAR_CLOSE */
$2 = $3 = $4 = $5 = $6 = $7 = $8 = NULL;
}
top-stream: top-stream opt-function-seq DEFINED ws-opt PAR_OPEN ws-opt FUNCTION ws-opt PAR_CLOSE {
*pp_output_chain = pptk_join(*pp_output_chain, $2); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $3); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $4); /* PAR_OPEN */
*pp_output_chain = pptk_join(*pp_output_chain, $5); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $6.tk_); /* FUNCTION */
*pp_output_chain = pptk_join(*pp_output_chain, $7); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $8); /* PAR_CLOSE */
$2 = $3 = $4 = $5 = $6.tk_ =$7 = $8 = NULL;
}
top-stream: top-stream opt-function-seq DEFINED ws-opt PAR_OPEN ws-opt OBJECT ws-opt PAR_CLOSE {
/* Insert "DEFINED (ID)" expansion; this is a straight up copy to preserve it for
* preprocessor constant expression evaluation. */
*pp_output_chain = pptk_join(*pp_output_chain, $2); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $3); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $4); /* PAR_OPEN */
*pp_output_chain = pptk_join(*pp_output_chain, $5); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $6.tk_); /* OBJECT */
*pp_output_chain = pptk_join(*pp_output_chain, $7); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $8); /* PAR_CLOSE */
$2 = $3 = $4 = $5 = $6.tk_ =$7 = $8 = NULL;
}
top-stream: top-stream opt-function-seq DEFINED ws-opt PAR_OPEN ws-opt DEFINED ws-opt PAR_CLOSE {
/* Insert "DEFINED (ID)" expansion; this is a straight up copy to preserve it for
* preprocessor constant expression evaluation. */
*pp_output_chain = pptk_join(*pp_output_chain, $2); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $3); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $4); /* PAR_OPEN */
*pp_output_chain = pptk_join(*pp_output_chain, $5); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $6); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $7); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $8); /* PAR_CLOSE */
$2 = $3 = $4 = $5 = $6 =$7 = $8 = NULL;
}
top-stream: top-stream opt-function-seq DEFINED ws-opt IDENT {
/* Insert "DEFINED ID" expansion; this is a straight up copy to preserve it for
* preprocessor constant expression evaluation. */
*pp_output_chain = pptk_join(*pp_output_chain, $2); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $3); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $4); /* IDENT */
$2 = $3 = $4 = NULL;
}
top-stream: top-stream opt-function-seq DEFINED ws-opt FUNCTION {
/* Insert "DEFINED ID" expansion; this is a straight up copy to preserve it for
* preprocessor constant expression evaluation. */
*pp_output_chain = pptk_join(*pp_output_chain, $2); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $3); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $4.tk_); /* FUNCTION */
$2 = $3 = $4.tk_ = NULL;
}
top-stream: top-stream opt-function-seq DEFINED ws-opt OBJECT {
/* Insert "DEFINED ID" expansion; this is a straight up copy to preserve it for
* preprocessor constant expression evaluation. */
*pp_output_chain = pptk_join(*pp_output_chain, $2); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $3); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $4.tk_); /* OBJECT */
$2 = $3 = $4.tk_ = NULL;
}
top-stream: top-stream opt-function-seq DEFINED ws-opt DEFINED {
/* Insert "DEFINED ID" expansion; this is a straight up copy to preserve it for
* preprocessor constant expression evaluation. */
*pp_output_chain = pptk_join(*pp_output_chain, $2); /* DEFINED */
*pp_output_chain = pptk_join(*pp_output_chain, $3); /* ws-opt */
*pp_output_chain = pptk_join(*pp_output_chain, $4); /* DEFINED */
$2 = $3 = $4 = NULL;
}
opt-function-seq: ws-opt-emit ;
opt-function-seq: opt-function-seq FUNCTION ws-opt {
/* Emit optional function sequences direct to output, they handle the edge case of a function-like
* macro with no arguments (which should not result in an expansion, but a literal copy of the
* macro identifier.) */
*pp_output_chain = pptk_join(*pp_output_chain, $1.tk_);
*pp_output_chain = pptk_join(*pp_output_chain, $2);
$1.tk_ = $2 = NULL;
}
args: arg {
struct macro_arg_inst *mai;
mai = macro_arg_inst_alloc($0);
if (!mai) {
dx_no_memory(pp->dx_);
return _PPME_NO_MEMORY;
}
$$ = mai; $0 = NULL;
}
args: args COMMA arg {
struct macro_arg_inst *mai;
mai = macro_arg_inst_alloc($2);
if (!mai) {
dx_no_memory(pp->dx_);
return _PPME_NO_MEMORY;
}
$2 = NULL;
$$ = macro_arg_inst_join($0, mai);
$0 = NULL;
}
arg: ;
arg: arg IDENT { $$ = pptk_join($0, $1); $0 = $1 = NULL; }
arg: arg FUNCTION { $$ = pptk_join($0, $1.tk_); $0 = $1.tk_ = NULL; }
arg: arg OBJECT { $$ = pptk_join($0, $1.tk_); $0 = $1.tk_ = NULL; }
arg: arg WS_TOK { $$ = pptk_join($0, $1); $0 = $1 = NULL; }
arg: arg OTHER { $$ = pptk_join($0, $1); $0 = $1 = NULL; }
arg: arg PAR_OPEN par-span PAR_CLOSE {
$$ = pptk_join($0, $1);
$$ = pptk_join($$, $2);
$$ = pptk_join($$, $3);
$0 = $1 = $2 = $3 = NULL;
}
/* par-span, like an arg, but with a comma allowed.. */
par-span: ;
par-span: par-span IDENT { $$ = pptk_join($0, $1); $0 = $1 = NULL; }
par-span: par-span FUNCTION { $$ = pptk_join($0, $1.tk_); $0 = $1.tk_ = NULL; }
par-span: par-span OBJECT { $$ = pptk_join($0, $1.tk_); $0 = $1.tk_ = NULL; }
par-span: par-span COMMA { $$ = pptk_join($0, $1); $0 = $1 = NULL; }
par-span: par-span WS_TOK { $$ = pptk_join($0, $1); $0 = $1 = NULL; }
par-span: par-span OTHER { $$ = pptk_join($0, $1); $0 = $1 = NULL; }
par-span: par-span PAR_OPEN par-span PAR_CLOSE {
$$ = pptk_join($0, $1);
$$ = pptk_join($$, $2);
$$ = pptk_join($$, $3);
$0 = $1 = $2 = $3 = NULL;
}
ws-opt-emit: ;
ws-opt-emit: ws-opt-emit WS_TOK {
*pp_output_chain = pptk_join(*pp_output_chain, $1);
$1 = NULL;
}
ws-opt:;
ws-opt: ws-opt WS_TOK {
$$ = pptk_join($0, $1);
$0 = $1 = NULL;
}