-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdepreprocessor.hh
708 lines (554 loc) · 20.3 KB
/
depreprocessor.hh
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
/*
* Copyright (C) 2019 SUSE Software Solutions Germany GmbH
*
* This file is part of klp-ccp.
*
* klp-ccp is free software: you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* klp-ccp is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with klp-ccp. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _DEPREPROCESSOR_HH
#define _DEPREPROCESSOR_HH
#include <string>
#include <map>
#include "pp_result.hh"
namespace klp
{
namespace ccp
{
class source_reader;
class source_writer;
class output_remarks;
class depreprocessor
{
private:
class _macro_define_to_emit;
struct _macro_undef_to_emit
{
_macro_undef_to_emit(const pp_result::macro_undef &_original) noexcept;
_macro_undef_to_emit(const std::string &_name);
bool operator<(const _macro_undef_to_emit& rhs) const noexcept;
bool operator<(const _macro_define_to_emit& rhs) const noexcept;
raw_pp_tokens_range get_range_raw() const noexcept;
const pp_result::macro_undef *original;
std::string name;
};
struct _macro_define_to_emit
{
_macro_define_to_emit(const pp_result::macro &_m) noexcept;
bool operator<(const _macro_define_to_emit& rhs) const noexcept;
bool operator<(const _macro_undef_to_emit& rhs) const noexcept;
raw_pp_tokens_range get_range_raw() const noexcept;
std::reference_wrapper<const pp_result::macro> m;
};
class _source_reader_cache
{
public:
source_reader& get(const pp_result::header_inclusion_node &h);
private:
std::vector<std::unique_ptr<source_reader>> _cache;
};
enum class _cond_incl_transition_kind
{
enter,
leave,
enter_leave,
};
struct _output_state
{
_output_state() noexcept;
const pp_result::header_inclusion_node *last_input_file;
raw_pp_token_index last_input_pos_raw;
bool last_was_newline;
};
public:
class transformed_input_chunk
{
public:
transformed_input_chunk(const pp_tokens_range &bounding_r);
void copy_subrange(const pp_tokens_range &r,
const bool need_whitespace_before,
const pp_tokens &toks);
void purge_subrange(const pp_tokens_range &r,
const bool need_whitespace_before);
void replace_token(const pp_token_index &index, pp_token &&repl_tok,
const bool add_pointer_deref);
void insert_token(const pp_token_index &pos, pp_token &&new_tok,
const bool need_whitespace_before,
const bool need_whitespace_after);
transformed_input_chunk split_head_off(const pp_tokens_range &r);
private:
friend class depreprocessor;
struct _op
{
public:
enum class sticky_side
{
none,
left,
right,
};
struct replaced_macro_arg_tok
{
raw_pp_token_index arg_tok;
pp_token new_tok;
bool add_pointer_deref;
};
typedef std::vector<replaced_macro_arg_tok>
replaced_macro_arg_toks_type;
_op(const pp_tokens_range &copied_range);
_op(const pp_tokens_range &replaced_range,
pp_token &&repl_tok, const bool _add_pointer_deref);
_op(const pp_token_index pos, pp_token &&_new_tok,
const sticky_side _stickiness);
_op(const pp_token_index pos, const sticky_side _stickiness);
_op(const pp_result::conditional_inclusion_node &_c,
const _cond_incl_transition_kind k,
const raw_pp_tokens_range &op_range_raw);
_op(const pp_tokens_range &expanded_macro_range,
const pp_result::macro_invocation *_rewritten_macro_invocation,
replaced_macro_arg_toks_type &&_replaced_macro_arg_toks);
bool operator<(const pp_tokens_range &rhs) const noexcept;
bool operator>(const pp_tokens_range &rhs) const noexcept;
raw_pp_tokens_range get_range_raw(const pp_result &pp_result)
const noexcept;
enum class action
{
copy,
replace,
insert,
insert_ws,
cond_incl_transition,
rewrite_macro_invocation,
};
action a;
pp_tokens_range r;
sticky_side stickiness;
pp_token new_tok;
bool add_pointer_deref;
const pp_result::conditional_inclusion_node *cond_incl_node;
_cond_incl_transition_kind cond_incl_trans_kind;
raw_pp_tokens_range cond_incl_op_range_raw;
const pp_result::macro_invocation *rewritten_macro_invocation;
replaced_macro_arg_toks_type replaced_macro_arg_toks;
};
typedef std::vector<_op> _ops_type;
struct _pos_in_chunk
{
_pos_in_chunk(const _ops_type::size_type _op,
const pp_token_index _tok) noexcept;
bool operator==(const _pos_in_chunk &rhs) const noexcept;
bool operator!=(const _pos_in_chunk &rhs) const noexcept
{ return !(*this == rhs); }
bool operator<(const _pos_in_chunk &rhs) const noexcept;
bool operator<=(const _pos_in_chunk &rhs) const noexcept
{ return *this < rhs || *this == rhs; }
_ops_type::size_type op;
pp_token_index tok;
};
struct _used_macro_in_chunk
{
_used_macro_in_chunk(const _pos_in_chunk &_pos,
const pp_result::macro &_m) noexcept;
_pos_in_chunk pos;
std::reference_wrapper<const pp_result::macro> m;
};
typedef std::vector<_used_macro_in_chunk>
_used_macros_in_chunk_type;
struct _macro_nondef_constraint_in_chunk
{
_macro_nondef_constraint_in_chunk
(const _pos_in_chunk &_pos,
pp_result::macro_nondef_constraint &&_mnc);
_pos_in_chunk pos;
pp_result::macro_nondef_constraint mnc;
};
typedef std::vector<_macro_nondef_constraint_in_chunk>
_macro_nondef_constraints_in_chunk_type;
struct _macro_undef_to_emit_in_chunk
{
_macro_undef_to_emit_in_chunk(const _pos_in_chunk &_pos,
_macro_undef_to_emit &&_mu);
bool operator<(const _macro_undef_to_emit_in_chunk &rhs)
const noexcept;
_pos_in_chunk pos;
_macro_undef_to_emit mu;
};
typedef std::vector<_macro_undef_to_emit_in_chunk>
_macro_undefs_to_emit_type;
struct _macro_define_to_emit_in_chunk
{
_macro_define_to_emit_in_chunk(const _pos_in_chunk &_pos,
_macro_define_to_emit &&_m);
bool operator<(const _macro_define_to_emit_in_chunk &rhs)
const noexcept;
_pos_in_chunk pos;
_macro_define_to_emit m;
};
typedef std::vector<_macro_define_to_emit_in_chunk>
_macro_defines_to_emit_type;
_ops_type::iterator _prepare_insert(const pp_tokens_range &r);
pp_tokens_range _get_range() const noexcept;
raw_pp_tokens_range _get_range_raw(const pp_result &pp_result)
const noexcept;
void _trim();
_pos_in_chunk _begin_pos_in_chunk() const noexcept;
_pos_in_chunk _end_pos_in_chunk() const noexcept;
_pos_in_chunk _next_pos_in_chunk(const _pos_in_chunk &cur_pos)
const noexcept;
std::pair<_ops_type::const_iterator, _ops_type::const_iterator>
_find_overlapping_ops_range(const raw_pp_tokens_range &r,
const pp_result &pp_result) const noexcept;
std::pair<_ops_type::iterator, _ops_type::iterator>
_find_overlapping_ops_range(const raw_pp_tokens_range &r,
const pp_result &pp_result) noexcept;
_pos_in_chunk _directive_range_to_pos_in_chunk
(const raw_pp_tokens_range &directive_range,
const pp_result &pp_result)
const noexcept;
bool _is_range_in_hole(const raw_pp_tokens_range &r,
const pp_result &pp_result) const noexcept;
void _insert_cond_incl_transition
(const pp_result::conditional_inclusion_node &c,
const _cond_incl_transition_kind k,
const pp_result &pp_result);
bool _find_macro_constraints(const pp_result &pp_result,
bool next_raw_tok_is_opening_parenthesis);
void
_try_rewrite_macro_arguments(const pp_result &pp_result,
const pp_result::macro_invocation &mi);
void _add_macro_undef_to_emit(const _pos_in_chunk &pos,
_macro_undef_to_emit &&mu);
void _add_macro_define_to_emit(const _pos_in_chunk &pos,
_macro_define_to_emit &&m);
bool _has_macro_undefs_or_defines_to_emit_before() const noexcept;
void
_write(source_writer &writer, _output_state &state,
const bool write_newlines_before,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache,
output_remarks &remarks) const;
pp_tokens_range _bounding_r;
_ops_type _ops;
_used_macros_in_chunk_type _used_macros_in_chunk;
_macro_nondef_constraints_in_chunk_type
_macro_nondef_constraints_in_chunk;
std::vector<pp_tokens_range> _ranges_to_emit_expanded;
_macro_undefs_to_emit_type _macro_undefs_to_emit;
_macro_defines_to_emit_type _macro_defines_to_emit;
};
depreprocessor(const pp_result &pp_result,
output_remarks &remarks);
void append(transformed_input_chunk &&tic);
void append(const pp_result::header_inclusion_child &include);
void append(const pp_result::header_inclusion_root &hir);
void operator()(const std::string &outfile);
private:
class _header_inclusion_chunk
{
private:
typedef std::vector<std::reference_wrapper<const pp_result::macro>>
_new_macro_defines_type;
public:
class const_new_macro_define_iterator :
public std::iterator<std::forward_iterator_tag,
const pp_result::macro>
{
public:
bool operator==(const const_new_macro_define_iterator &rhs)
const noexcept
{ return this->_it == rhs._it; }
bool operator!=(const const_new_macro_define_iterator &rhs)
const noexcept
{
return !(*this == rhs);
}
reference operator*() const noexcept
{ return _it->get(); }
pointer operator->() const noexcept
{ return &_it->get(); }
const_new_macro_define_iterator& operator++() noexcept
{ ++_it; return *this; }
const const_new_macro_define_iterator operator++(int) noexcept
{ return const_new_macro_define_iterator{_it++}; }
private:
friend class _header_inclusion_chunk;
const_new_macro_define_iterator
(const _new_macro_defines_type::const_iterator &it) noexcept
: _it(it)
{}
_new_macro_defines_type::const_iterator _it;
};
_header_inclusion_chunk
(const pp_result::header_inclusion_child &child_node);
_header_inclusion_chunk
(const pp_result::header_inclusion_root &root_node);
const pp_result::header_inclusion_node& get_inclusion_node()
const noexcept;
void find_macro_constraints(const pp_result &pp_result);
bool needs_undef_before_include(const pp_result::macro &m)
const noexcept;
bool is_unmodified_by_include(const pp_result::macro &m) const noexcept;
const_new_macro_define_iterator new_macro_defines_begin() const noexcept
{ return const_new_macro_define_iterator{_new_macro_defines.begin()}; }
const_new_macro_define_iterator new_macro_defines_end() const noexcept
{ return const_new_macro_define_iterator{_new_macro_defines.end()}; }
const pp_result::used_macros& get_used_macros() const noexcept
{ return _used_macros; }
void add_macro_undef_to_emit(_macro_undef_to_emit &&mu);
void add_macro_define_to_emit(_macro_define_to_emit &&m);
bool has_macro_undefs_or_defines_to_emit() const noexcept;
void write(source_writer &writer, _output_state &state,
const bool write_newlines_before,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache,
output_remarks &remarks) const;
private:
enum class _kind
{
k_child,
k_root,
};
_kind _k;
union
{
const pp_result::header_inclusion_child *_child_node;
const pp_result::header_inclusion_root *_root_node;
};
pp_result::macro_nondef_constraints _macro_nondef_constraints;
std::map<std::string, std::reference_wrapper<const pp_result::macro>>
_macro_defines_wo_prior_undef;
std::set<std::string> _macro_undefs;
_new_macro_defines_type _new_macro_defines;
pp_result::used_macros _used_macros;
std::vector<_macro_undef_to_emit> _macro_undefs_to_emit;
std::vector<_macro_define_to_emit> _macro_defines_to_emit;
};
class _cond_incl_transition_chunk
{
public:
_cond_incl_transition_chunk
(const pp_result::conditional_inclusion_node &c,
const _cond_incl_transition_kind k) noexcept;
raw_pp_tokens_range get_range_raw() const noexcept;
_cond_incl_transition_kind get_kind() const noexcept
{ return _k; }
const pp_result::used_macros& get_used_macros() const noexcept;
const pp_result::macro_nondef_constraints&
get_macro_nondef_constraints() const noexcept;
void add_macro_undef_to_emit(_macro_undef_to_emit &&mu);
void add_macro_define_to_emit(_macro_define_to_emit &&m);
bool has_macro_undefs_or_defines_to_emit() const noexcept;
void write(source_writer &writer,
_output_state &state,
const bool write_newlines_before,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache,
output_remarks &remarks) const;
private:
std::reference_wrapper<const pp_result::conditional_inclusion_node> _c;
_cond_incl_transition_kind _k;
std::vector<_macro_undef_to_emit> _macro_undefs_to_emit;
std::vector<_macro_define_to_emit> _macro_defines_to_emit;
};
struct _chunk
{
enum class kind
{
transformed_input,
header_inclusion,
cond_incl_transition,
_dead,
};
_chunk(transformed_input_chunk &&_tic, const pp_result &pp_result);
_chunk(_header_inclusion_chunk &&_hic);
_chunk(_cond_incl_transition_chunk &&_cic);
_chunk(_chunk &&c);
~_chunk() noexcept;
_chunk& operator=(_chunk &&rhs);
kind k;
union
{
transformed_input_chunk tic;
_header_inclusion_chunk hic;
_cond_incl_transition_chunk cic;
};
raw_pp_tokens_range range_raw;
};
typedef std::vector<_chunk> _chunks_type;
struct _in_order_chunk
{
_in_order_chunk(const _chunks_type::iterator _it_chunk) noexcept;
_chunks_type::iterator it_chunk;
raw_pp_tokens_range attributed_range_raw;
};
typedef std::vector<_in_order_chunk> _in_order_chunks_type;
struct _pos_in_output
{
_pos_in_output
(const _chunks_type::iterator &_chunk,
const transformed_input_chunk::_pos_in_chunk &_pos_in_chunk)
noexcept;
_pos_in_output(const _chunks_type::iterator &_chunk) noexcept;
bool operator==(const _pos_in_output &rhs) const noexcept;
bool operator!=(const _pos_in_output &rhs) const noexcept
{ return !(*this == rhs); }
bool operator<(const _pos_in_output &rhs) const noexcept;
bool operator<=(const _pos_in_output &rhs) const noexcept
{ return *this < rhs || *this == rhs; }
_chunks_type::iterator chunk;
transformed_input_chunk::_pos_in_chunk pos_in_chunk;
};
struct _macro_state
{
_macro_state(const pp_result::macro &_m,
const _pos_in_output &_last_usage) noexcept;
std::reference_wrapper<const pp_result::macro> m;
_pos_in_output last_usage;
};
typedef std::map<std::string, _macro_state> _macro_states_type;
private:
friend class transformed_input_chunk;
friend class _header_inclusion_chunk;
void _try_merge_chunks_pre();
void _compute_needed_macro_defs_and_undefs();
void _compute_needed_macro_defs_and_undefs_tic
(const _chunks_type::iterator &it_chunk,
const _in_order_chunks_type &in_order_chunks,
const _chunks_type::iterator &cur_run_begin,
_macro_states_type ¯o_states);
void _compute_needed_macro_defs_and_undefs_hic
(const _chunks_type::iterator &it_chunk,
const _in_order_chunks_type &in_order_chunks,
const _chunks_type::iterator &cur_run_begin,
_macro_states_type ¯o_states);
void _compute_needed_macro_defs_and_undefs_cic
(const _chunks_type::iterator &it_chunk,
const _in_order_chunks_type &in_order_chunks,
const _chunks_type::iterator &cur_run_begin,
_macro_states_type ¯o_states);
void _emit_undef(const _macro_state ¯o_state,
const _pos_in_output &mnc_pos,
const _in_order_chunks_type &in_order_chunks,
const _chunks_type::iterator &cur_run_begin);
void _emit_define(const pp_result::macro &m,
const _pos_in_output &um_pos,
const _in_order_chunks_type &in_order_chunks,
const _chunks_type::iterator &cur_run_begin,
const _macro_state * const conflicting_macro_state);
bool _can_place_define_at
(const pp_result::macro &m,
const _pos_in_output &placement_pos,
const _pos_in_output &um_pos,
const _macro_state * const conflicting_macro_state) noexcept;
bool _can_place_undef_at(const std::string &name,
const _pos_in_output &placement_pos,
const _pos_in_output &mnc_pos,
const _pos_in_output &last_macro_usage) noexcept;
_pos_in_output _find_macro_undef_in_order_pos
(const pp_result::macro_undef &mu,
const _in_order_chunks_type &in_order_chunks)
noexcept;
_pos_in_output _find_macro_define_in_order_pos
(const pp_result::macro &m,
const _in_order_chunks_type &in_order_chunks)
noexcept;
_pos_in_output
_find_directive_in_order_pos(const raw_pp_tokens_range &directive_range,
const _in_order_chunks_type &in_order_chunks)
noexcept;
_pos_in_output
_find_macro_undef_in_run_pos(const pp_result::macro_undef &mu,
const _chunks_type::iterator &run_begin,
const _chunks_type::iterator &run_end)
noexcept;
_pos_in_output
_find_macro_define_in_run_pos(const pp_result::macro &m,
const _chunks_type::iterator &run_begin,
const _chunks_type::iterator &run_end)
noexcept;
_pos_in_output
_find_directive_in_run_pos(const raw_pp_tokens_range &directive_range,
const _chunks_type::iterator &run_begin,
const _chunks_type::iterator &run_end)
noexcept;
_pos_in_output
_chunk_pos_in_output(const _chunks_type::iterator &it_chunk)
noexcept;
_pos_in_output _end_pos_in_output() noexcept;
static void _set_input_file(source_writer &writer, _output_state &state,
const pp_result::header_inclusion_node *h);
static void _write_newlines(source_writer &writer, _output_state &state,
const raw_pp_token_index next_begin_raw,
const bool need_newline,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache);
static void _write_directive(source_writer &writer, _output_state &state,
const raw_pp_tokens_range &directive_range,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache);
static void _write_define(source_writer &writer, _output_state &state,
const _macro_define_to_emit &md,
const bool write_newlines_before,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache,
output_remarks &remarks);
static void _write_undef(source_writer &writer, _output_state &state,
const _macro_undef_to_emit &mu,
const bool write_newlines_before,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache);
static void
_write_defines_and_undefs(source_writer &writer, _output_state &state,
const std::vector<_macro_define_to_emit> &mds,
const std::vector<_macro_undef_to_emit> &mus,
const bool write_newlines_before,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache,
output_remarks &remarks);
typedef std::vector
<std::reference_wrapper
<const pp_result::conditional_inclusion_node>>
_cond_incl_stack_type;
bool
_is_cond_incl_header_guard(const pp_result::conditional_inclusion_node &c)
const noexcept;
_cond_incl_stack_type
_build_cond_incl_stack(const pp_result::conditional_inclusion_node &c)
const;
static _cond_incl_stack_type::size_type
_cond_incl_stacks_common_length(const _cond_incl_stack_type &s1,
const _cond_incl_stack_type &s2) noexcept;
void _prepare_cond_incls(transformed_input_chunk &tic);
void _prepare_cond_incls(const pp_result::header_inclusion_child &h);
void _leave_cond_incls(const _cond_incl_stack_type::size_type nkeep);
void _enter_cond_incl(const pp_result::conditional_inclusion_node &c);
static raw_pp_tokens_range
_get_cond_incl_trans_range_raw
(const pp_result::conditional_inclusion_node &c,
const _cond_incl_transition_kind k) noexcept;
static void
_write_cond_incl_transition
(source_writer &writer, _output_state &state,
const pp_result::conditional_inclusion_node &c,
const _cond_incl_transition_kind k,
const bool write_newlines_before,
const pp_result &pp_result,
_source_reader_cache &source_reader_cache,
output_remarks &remarks);
const pp_result &_pp_result;
_chunks_type _chunks;
output_remarks &_remarks;
_cond_incl_stack_type _cond_incl_stack;
};
}
}
#endif