6
6
7
7
\*******************************************************************/
8
8
9
+ #include < algorithm>
9
10
#include < fstream>
10
11
11
12
#include < util/config.h>
12
13
13
14
#include " verilog_preprocessor.h"
14
15
16
+ void verilog_preprocessort::definet::replace_substring (
17
+ std::string &source, const std::string &orig_sub,
18
+ const std::string &new_sub) const {
19
+ PRECONDITION (!orig_sub.empty ());
20
+ PRECONDITION (!new_sub.empty ());
21
+
22
+ std::size_t index = 0 ;
23
+ auto const orig_sub_size = orig_sub.size ();
24
+ auto const new_sub_size = new_sub.size ();
25
+
26
+ while (true ) {
27
+ index = source.find (orig_sub, index);
28
+ if (index == std::string::npos)
29
+ break ;
30
+
31
+ source.replace (index, orig_sub_size, new_sub);
32
+ index += new_sub_size;
33
+ }
34
+ }
35
+
36
+ std::string verilog_preprocessort::definet::replace_macro (
37
+ const std::string &arg_string) const {
38
+ std::vector<std::string> arguments =
39
+ split_string (arg_string, ' ,' , true , true );
40
+ PRECONDITION (arguments.size () == parameters.size ());
41
+
42
+ if (parameters.size () == 1 && parameters.back ().empty ())
43
+ return value;
44
+
45
+ auto longer_first = [](const std::string &left, const std::string &right) {
46
+ if (left.size () > right.size ())
47
+ return true ;
48
+ return std::lexicographical_compare (left.begin (), left.end (), right.begin (),
49
+ right.end ());
50
+ };
51
+
52
+ std::map<std::string, std::string, decltype (longer_first)> param_to_arg{
53
+ longer_first};
54
+
55
+ for (std::size_t i = 0 ; i < parameters.size (); ++i) {
56
+ param_to_arg.emplace (parameters[i], arguments[i]);
57
+ }
58
+
59
+ std::string result_value = value;
60
+ for (auto const ¶m_arg_pair : param_to_arg) {
61
+ replace_substring (result_value, param_arg_pair.first ,
62
+ param_arg_pair.second );
63
+ }
64
+ return result_value;
65
+ }
66
+
67
+ optionalt<std::size_t >
68
+ verilog_preprocessort::find_define (const std::string &name) const {
69
+ std::size_t define_index = 0 ;
70
+ for (; define_index != defines.size (); ++define_index) {
71
+ if (defines[define_index].identifier == name)
72
+ return define_index;
73
+ }
74
+ return {};
75
+ }
76
+
15
77
/* ******************************************************************\
16
78
17
79
Function: verilog_preprocessort::getline
@@ -301,18 +363,42 @@ void verilog_preprocessort::replace_macros(std::string &s)
301
363
i++;
302
364
303
365
std::string text (s, start, i-start);
366
+ std::string arg_string;
367
+
368
+ unsigned i_before_whitespace_skip = i;
369
+ // skip whitespace
370
+ while (s[i] == ' ' || s[i] == ' \t ' || s[i] == ' \n ' )
371
+ ++i;
372
+
373
+ // maybe read the arguments
374
+ if (s[i] == ' (' ) {
375
+ std::size_t level = 0 ;
376
+
377
+ // find the matching parenthesis, everything between is the argument
378
+ // list
379
+ while (s[++i] != ' )' || level != 0 ) {
380
+ arg_string += s[i];
381
+
382
+ if (s[i] == ' (' )
383
+ ++level;
384
+ else if (s[i] == ' )' )
385
+ --level;
386
+ }
387
+ // now s[i]==')' -> let's move one more
388
+ ++i;
389
+ } else {
390
+ // just in case the whitespace was important
391
+ i = i_before_whitespace_skip;
392
+ }
304
393
305
- definest::const_iterator it=defines.find (text);
306
-
307
- if (it==defines.end ())
308
- {
394
+ auto maybe_define_index = find_define (text);
395
+ if (!maybe_define_index.has_value ()) {
309
396
error () << " unknown preprocessor macro \" " << text << " \" " << eom;
310
397
throw 0 ;
311
398
}
312
399
313
400
// found it! replace it!
314
-
315
- dest+=it->second ;
401
+ dest += defines[*maybe_define_index].replace_macro (arg_string);
316
402
}
317
403
else
318
404
{
@@ -353,6 +439,40 @@ void verilog_preprocessort::directive()
353
439
}
354
440
}
355
441
442
+ std::string arg_string;
443
+
444
+ size_t unget_counter = 0 ;
445
+ // skip whitespace
446
+ while (files.back ().in ->get (ch)) {
447
+ ++unget_counter;
448
+ if (ch == ' ' || ch == ' \t ' || ch == ' \n ' )
449
+ ;
450
+ else
451
+ break ;
452
+ }
453
+
454
+ // maybe read the arguments
455
+ if (ch == ' (' ) {
456
+ std::size_t level = 0 ;
457
+
458
+ // find the matching parenthesis, everything between is the argument
459
+ // list
460
+ while (files.back ().in ->get (ch)) {
461
+ if (level == 0 && ch == ' )' ) {
462
+ break ;
463
+ }
464
+ arg_string += ch;
465
+ if (ch == ' (' )
466
+ ++level;
467
+ else if (ch == ' )' )
468
+ --level;
469
+ }
470
+ } else {
471
+ // just in case the whitespace was important
472
+ while (unget_counter-- > 0 )
473
+ files.back ().in ->unget ();
474
+ }
475
+
356
476
std::string line;
357
477
358
478
if (text==" define" )
@@ -367,7 +487,7 @@ void verilog_preprocessort::directive()
367
487
// skip whitespace
368
488
while (*tptr==' ' || *tptr==' \t ' ) tptr++;
369
489
370
- std::string identifier, value;
490
+ std::string identifier, param_string, value;
371
491
372
492
// copy identifier
373
493
while (isalnum (*tptr) || *tptr==' $' || *tptr==' _' )
@@ -379,8 +499,9 @@ void verilog_preprocessort::directive()
379
499
// is there a parameter list?
380
500
if (*tptr==' (' )
381
501
{
382
- error () << " `define with parameters not yet supported" << eom;
383
- throw 0 ;
502
+ while (*(++tptr) != ' )' )
503
+ param_string.push_back (*tptr);
504
+ ++tptr; // get past the closing parenthesis
384
505
}
385
506
386
507
// skip whitespace
@@ -401,7 +522,7 @@ void verilog_preprocessort::directive()
401
522
<< " < = >" << value << " <" << std::endl;
402
523
#endif
403
524
404
- defines[ identifier]= value;
525
+ defines. emplace_back ( identifier, param_string, value) ;
405
526
}
406
527
else if (text==" undef" )
407
528
{
@@ -424,13 +545,9 @@ void verilog_preprocessort::directive()
424
545
tptr++;
425
546
}
426
547
427
- definest::iterator it=defines.find (identifier);
428
-
429
- if (it!=defines.end ())
430
- {
431
- // found it! remove it!
432
-
433
- defines.erase (it);
548
+ auto maybe_define_index = find_define (identifier);
549
+ if (maybe_define_index.has_value ()) {
550
+ defines.erase (defines.begin () + *maybe_define_index);
434
551
}
435
552
}
436
553
else if (text==" ifdef" || text==" ifndef" )
@@ -451,15 +568,15 @@ void verilog_preprocessort::directive()
451
568
tptr++;
452
569
}
453
570
454
- definest::iterator it=defines. find (identifier);
571
+ auto maybe_define_index = find_define (identifier);
455
572
456
573
conditionalt conditional;
457
574
458
575
if (text==" ifdef" )
459
- conditional.condition =(it!=defines. end () );
576
+ conditional.condition = maybe_define_index. has_value ( );
460
577
else
461
- conditional.condition =(it==defines. end () );
462
-
578
+ conditional.condition = !maybe_define_index. has_value ( );
579
+
463
580
conditional.previous_condition =condition;
464
581
conditionals.push_back (conditional);
465
582
condition=conditional.get_cond ();
@@ -562,17 +679,15 @@ void verilog_preprocessort::directive()
562
679
563
680
if (condition)
564
681
{
565
- definest::const_iterator it=defines.find (text);
566
-
567
- if (it==defines.end ())
568
- {
682
+ auto maybe_define_index = find_define (text);
683
+ if (!maybe_define_index.has_value ()) {
569
684
error () << " unknown preprocessor directive \" " << text << " \" " << eom;
570
685
throw 0 ;
571
686
}
572
687
573
688
// found it! replace it!
574
689
575
- out << it-> second ;
690
+ out << defines[*maybe_define_index]. replace_macro (arg_string) ;
576
691
}
577
692
}
578
693
}
0 commit comments