Merge pull request #3310 from robinsonb5-PRs/master
[yosys.git] / frontends / verilog / preproc.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * ---
19 *
20 * The Verilog frontend.
21 *
22 * This frontend is using the AST frontend library (see frontends/ast/).
23 * Thus this frontend does not generate RTLIL code directly but creates an
24 * AST directly from the Verilog parse tree and then passes this AST to
25 * the AST frontend library.
26 *
27 * ---
28 *
29 * Ad-hoc implementation of a Verilog preprocessor. The directives `define,
30 * `include, `ifdef, `ifndef, `else and `endif are handled here. All other
31 * directives are handled by the lexer (see verilog_lexer.l).
32 *
33 */
34
35 #include "preproc.h"
36 #include "verilog_frontend.h"
37 #include "kernel/log.h"
38 #include <assert.h>
39 #include <stack>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <string.h>
43
44 YOSYS_NAMESPACE_BEGIN
45 using namespace VERILOG_FRONTEND;
46
47 static std::list<std::string> output_code;
48 static std::list<std::string> input_buffer;
49 static size_t input_buffer_charp;
50
51 static void return_char(char ch)
52 {
53 if (input_buffer_charp == 0)
54 input_buffer.push_front(std::string() + ch);
55 else
56 input_buffer.front()[--input_buffer_charp] = ch;
57 }
58
59 static void insert_input(std::string str)
60 {
61 if (input_buffer_charp != 0) {
62 input_buffer.front() = input_buffer.front().substr(input_buffer_charp);
63 input_buffer_charp = 0;
64 }
65 input_buffer.push_front(str);
66 }
67
68 static char next_char()
69 {
70 if (input_buffer.empty())
71 return 0;
72
73 log_assert(input_buffer_charp <= input_buffer.front().size());
74 if (input_buffer_charp == input_buffer.front().size()) {
75 input_buffer_charp = 0;
76 input_buffer.pop_front();
77 return next_char();
78 }
79
80 char ch = input_buffer.front()[input_buffer_charp++];
81 return ch == '\r' ? next_char() : ch;
82 }
83
84 static std::string skip_spaces()
85 {
86 std::string spaces;
87 while (1) {
88 char ch = next_char();
89 if (ch == 0)
90 break;
91 if (ch != ' ' && ch != '\t') {
92 return_char(ch);
93 break;
94 }
95 spaces += ch;
96 }
97 return spaces;
98 }
99
100 static std::string next_token(bool pass_newline = false)
101 {
102 std::string token;
103
104 char ch = next_char();
105 if (ch == 0)
106 return token;
107
108 token += ch;
109 if (ch == '\n') {
110 if (pass_newline) {
111 output_code.push_back(token);
112 return "";
113 }
114 return token;
115 }
116
117 if (ch == ' ' || ch == '\t')
118 {
119 while ((ch = next_char()) != 0) {
120 if (ch != ' ' && ch != '\t') {
121 return_char(ch);
122 break;
123 }
124 token += ch;
125 }
126 }
127 else if (ch == '"')
128 {
129 while ((ch = next_char()) != 0) {
130 token += ch;
131 if (ch == '"')
132 break;
133 if (ch == '\\') {
134 if ((ch = next_char()) != 0)
135 token += ch;
136 }
137 }
138 if (token == "\"\"" && (ch = next_char()) != 0) {
139 if (ch == '"')
140 token += ch;
141 else
142 return_char(ch);
143 }
144 }
145 else if (ch == '\\')
146 {
147 while ((ch = next_char()) != 0) {
148 if (ch < 33 || ch > 126) {
149 return_char(ch);
150 break;
151 }
152 token += ch;
153 }
154 }
155 else if (ch == '/')
156 {
157 if ((ch = next_char()) != 0) {
158 if (ch == '/') {
159 token += '*';
160 char last_ch = 0;
161 while ((ch = next_char()) != 0) {
162 if (ch == '\n') {
163 return_char(ch);
164 break;
165 }
166 if (last_ch != '*' || ch != '/') {
167 token += ch;
168 last_ch = ch;
169 }
170 }
171 token += " */";
172 }
173 else if (ch == '*') {
174 token += '*';
175 int newline_count = 0;
176 char last_ch = 0;
177 while ((ch = next_char()) != 0) {
178 if (ch == '\n') {
179 newline_count++;
180 token += ' ';
181 } else
182 token += ch;
183 if (last_ch == '*' && ch == '/')
184 break;
185 last_ch = ch;
186 }
187 while (newline_count-- > 0)
188 return_char('\n');
189 }
190 else
191 return_char(ch);
192 }
193 }
194 else
195 {
196 const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789";
197 if (ch == '`' || strchr(ok, ch) != NULL)
198 {
199 char first = ch;
200 ch = next_char();
201 if (first == '`' && (ch == '"' || ch == '`')) {
202 token += ch;
203 } else do {
204 if (strchr(ok, ch) == NULL) {
205 return_char(ch);
206 break;
207 }
208 token += ch;
209 } while ((ch = next_char()) != 0);
210 }
211 }
212 return token;
213 }
214
215 struct macro_arg_t
216 {
217 macro_arg_t(const std::string &name_, const char *default_value_)
218 : name(name_),
219 has_default(default_value_ != nullptr),
220 default_value(default_value_ ? default_value_ : "")
221 {}
222
223 std::string name;
224 bool has_default;
225 std::string default_value;
226 };
227
228 static bool all_white(const std::string &str)
229 {
230 for (char c : str)
231 if (!isspace(c))
232 return false;
233 return true;
234 }
235
236 struct arg_map_t
237 {
238 arg_map_t()
239 {}
240
241 void add_arg(const std::string &name, const char *default_value)
242 {
243 if (find(name)) {
244 log_error("Duplicate macro arguments with name `%s'.\n", name.c_str());
245 }
246
247 name_to_pos[name] = args.size();
248 args.push_back(macro_arg_t(name, default_value));
249 }
250
251 // Find an argument by name; return nullptr if it doesn't exist. If pos is not null, write
252 // the argument's position to it on success.
253 const macro_arg_t *find(const std::string &name, int *pos = nullptr) const
254 {
255 auto it = name_to_pos.find(name);
256 if (it == name_to_pos.end())
257 return nullptr;
258
259 if (pos) *pos = it->second;
260 return &args[it->second];
261 }
262
263 // Construct the name for the local macro definition we use for the given argument
264 // (something like macro_foobar_arg2). This doesn't include the leading backtick.
265 static std::string str_token(const std::string &macro_name, int pos)
266 {
267 return stringf("macro_%s_arg%d", macro_name.c_str(), pos);
268 }
269
270 // Return definitions for the macro arguments (so that substituting in the macro body and
271 // then performing macro expansion will do argument substitution properly).
272 std::vector<std::pair<std::string, std::string>>
273 get_vals(const std::string &macro_name, const std::vector<std::string> &arg_vals) const
274 {
275 std::vector<std::pair<std::string, std::string>> ret;
276 for (int i = 0; i < GetSize(args); ++ i) {
277 // The SystemVerilog rules are:
278 //
279 // - If the call site specifies an argument and it's not whitespace, use
280 // it.
281 //
282 // - Otherwise, if the argument has a default value, use it.
283 //
284 // - Otherwise, if the call site specified whitespace, use that.
285 //
286 // - Otherwise, error.
287 const std::string *dflt = nullptr;
288 if (args[i].has_default)
289 dflt = &args[i].default_value;
290
291 const std::string *given = nullptr;
292 if (i < GetSize(arg_vals))
293 given = &arg_vals[i];
294
295 const std::string *val = nullptr;
296 if (given && (! (dflt && all_white(*given))))
297 val = given;
298 else if (dflt)
299 val = dflt;
300 else if (given)
301 val = given;
302 else
303 log_error("Cannot expand macro `%s by giving only %d argument%s "
304 "(argument %d has no default).\n",
305 macro_name.c_str(), GetSize(arg_vals),
306 (GetSize(arg_vals) == 1 ? "" : "s"), i + 1);
307
308 assert(val);
309 ret.push_back(std::make_pair(str_token(macro_name, i), * val));
310 }
311 return ret;
312 }
313
314
315 std::vector<macro_arg_t> args;
316 std::map<std::string, int> name_to_pos;
317 };
318
319 struct define_body_t
320 {
321 define_body_t(const std::string &body, const arg_map_t *args = nullptr)
322 : body(body),
323 has_args(args != nullptr),
324 args(args ? *args : arg_map_t())
325 {}
326
327 std::string body;
328 bool has_args;
329 arg_map_t args;
330 };
331
332 define_map_t::define_map_t()
333 {
334 add("YOSYS", "1");
335 }
336
337 // We must define this destructor here (rather than relying on the default), because we need to
338 // define it somewhere we've got a complete definition of define_body_t.
339 define_map_t::~define_map_t()
340 {}
341
342 void
343 define_map_t::add(const std::string &name, const std::string &txt, const arg_map_t *args)
344 {
345 defines[name] = std::unique_ptr<define_body_t>(new define_body_t(txt, args));
346 }
347
348 void define_map_t::add(const std::string &name, const define_body_t &body)
349 {
350 defines[name] = std::unique_ptr<define_body_t>(new define_body_t(body));
351 }
352
353 void define_map_t::merge(const define_map_t &map)
354 {
355 for (const auto &pr : map.defines) {
356 // These contortions are so that we take a copy of each definition body in
357 // map.defines.
358 defines[pr.first] = std::unique_ptr<define_body_t>(new define_body_t(*pr.second));
359 }
360 }
361
362 const define_body_t *define_map_t::find(const std::string &name) const
363 {
364 auto it = defines.find(name);
365 return (it == defines.end()) ? nullptr : it->second.get();
366 }
367
368 void define_map_t::erase(const std::string &name)
369 {
370 defines.erase(name);
371 }
372
373 void define_map_t::clear()
374 {
375 defines.clear();
376 }
377
378 void define_map_t::log() const
379 {
380 for (auto &it : defines) {
381 const std::string &name = it.first;
382 const define_body_t &body = *it.second;
383 Yosys::log("`define %s%s %s\n",
384 name.c_str(), body.has_args ? "()" : "", body.body.c_str());
385 }
386 }
387
388 static void input_file(std::istream &f, std::string filename)
389 {
390 char buffer[513];
391 int rc;
392
393 insert_input("");
394 auto it = input_buffer.begin();
395
396 input_buffer.insert(it, "`file_push \"" + filename + "\"\n");
397 while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) {
398 buffer[rc] = 0;
399 input_buffer.insert(it, buffer);
400 }
401 input_buffer.insert(it, "\n`file_pop\n");
402 }
403
404 // Read tokens to get one argument (either a macro argument at a callsite or a default argument in a
405 // macro definition). Writes the argument to dest. Returns true if we finished with ')' (the end of
406 // the argument list); false if we finished with ','.
407 static bool read_argument(std::string &dest)
408 {
409 skip_spaces();
410 std::vector<char> openers;
411 for (;;) {
412 std::string tok = next_token(true);
413 if (tok == ")") {
414 if (openers.empty()) {
415 while (dest.size() && (dest.back() == ' ' || dest.back() == '\t'))
416 dest = dest.substr(0, dest.size() - 1);
417 return true;
418 }
419 if (openers.back() != '(')
420 log_error("Mismatched brackets in macro argument: %c and %c.\n",
421 openers.back(), tok[0]);
422
423 openers.pop_back();
424 dest += tok;
425 continue;
426 }
427 if (tok == "]") {
428 char opener = openers.empty() ? '(' : openers.back();
429 if (opener != '[')
430 log_error("Mismatched brackets in macro argument: %c and %c.\n",
431 opener, tok[0]);
432
433 openers.pop_back();
434 dest += tok;
435 continue;
436 }
437 if (tok == "}") {
438 char opener = openers.empty() ? '(' : openers.back();
439 if (opener != '{')
440 log_error("Mismatched brackets in macro argument: %c and %c.\n",
441 opener, tok[0]);
442
443 openers.pop_back();
444 dest += tok;
445 continue;
446 }
447
448 if (tok == "," && openers.empty()) {
449 return false;
450 }
451
452 if (tok == "(" || tok == "[" || tok == "{")
453 openers.push_back(tok[0]);
454
455 dest += tok;
456 }
457 }
458
459 using macro_arg_stack_t = std::stack<std::pair<std::string, define_body_t>>;
460
461 static void restore_macro_arg(define_map_t &defines, macro_arg_stack_t &macro_arg_stack)
462 {
463 log_assert(!macro_arg_stack.empty());
464 auto &overwritten_arg = macro_arg_stack.top();
465 defines.add(overwritten_arg.first, overwritten_arg.second);
466 macro_arg_stack.pop();
467 }
468
469 static bool try_expand_macro(define_map_t &defines, macro_arg_stack_t &macro_arg_stack, std::string &tok)
470 {
471 if (tok == "`\"") {
472 std::string literal("\"");
473 // Expand string literal
474 while (!input_buffer.empty()) {
475 std::string ntok = next_token();
476 if (ntok == "`\"") {
477 insert_input(literal+"\"");
478 return true;
479 } else if (!try_expand_macro(defines, macro_arg_stack, ntok)) {
480 literal += ntok;
481 }
482 }
483 return false; // error - unmatched `"
484 }
485
486 if (tok == "``") {
487 // Swallow `` in macro expansion
488 return true;
489 }
490
491 if (tok.size() <= 1 || tok[0] != '`')
492 return false;
493
494 // This token looks like a macro name (`foo).
495 std::string macro_name = tok.substr(1);
496 const define_body_t *body = defines.find(tok.substr(1));
497
498 if (! body) {
499 // Apparently not a name we know.
500 return false;
501 }
502
503 std::string name = tok.substr(1);
504 std::string skipped_spaces = skip_spaces();
505 tok = next_token(false);
506 if (body->has_args) {
507 if (tok != "(") {
508 if (tok.size() == 1 && iscntrl(tok[0])) {
509 char buf[5];
510 snprintf(buf, sizeof(buf), "\\x%02x", tok[0]);
511 tok = buf;
512 }
513 log_error("Expected to find '(' to begin macro arguments for '%s', but instead found '%s'\n",
514 name.c_str(), tok.c_str());
515 }
516 std::vector<std::string> args;
517 bool done = false;
518 while (!done) {
519 std::string arg;
520 done = read_argument(arg);
521 args.push_back(arg);
522 }
523 for (const auto &pr : body->args.get_vals(name, args)) {
524 if (const define_body_t *existing = defines.find(pr.first)) {
525 macro_arg_stack.push({pr.first, *existing});
526 insert_input("`__restore_macro_arg ");
527 }
528 defines.add(pr.first, pr.second);
529 }
530 } else {
531 insert_input(tok);
532 insert_input(skipped_spaces);
533 }
534 insert_input(body->body);
535 return true;
536 }
537
538 // Read the arguments for a `define preprocessor directive with formal arguments. This is called
539 // just after reading the token containing "(". Returns the number of newlines to emit afterwards to
540 // keep line numbers in sync, together with the map from argument name to data (pos and default
541 // value).
542 static std::pair<int, arg_map_t>
543 read_define_args()
544 {
545 // Each argument looks like one of the following:
546 //
547 // identifier
548 // identifier = default_text
549 // identifier =
550 //
551 // The first example is an argument with no default value. The second is an argument whose
552 // default value is default_text. The third is an argument with default value the empty
553 // string.
554
555 int newline_count = 0;
556 arg_map_t args;
557
558 // FSM state.
559 //
560 // 0: At start of identifier
561 // 1: After identifier (stored in arg_name)
562 // 2: After closing paren
563 int state = 0;
564
565 std::string arg_name, default_val;
566
567 skip_spaces();
568 for (;;) {
569 if (state == 2)
570 // We've read the closing paren.
571 break;
572
573 std::string tok = next_token();
574
575 // Cope with escaped EOLs
576 if (tok == "\\") {
577 char ch = next_char();
578 if (ch == '\n') {
579 // Eat the \, the \n and any trailing space and keep going.
580 skip_spaces();
581 continue;
582 } else {
583 // There aren't any other situations where a backslash makes sense.
584 log_error("Backslash in macro arguments (not at end of line).\n");
585 }
586 }
587
588 switch (state) {
589 case 0:
590 // At start of argument. If the token is ')', we've presumably just seen
591 // something like "`define foo() ...". Set state to 2 to finish. Otherwise,
592 // the token should be a valid simple identifier, but we'll allow anything
593 // here.
594 if (tok == ")") {
595 state = 2;
596 } else {
597 arg_name = tok;
598 state = 1;
599 }
600 skip_spaces();
601 break;
602
603 case 1:
604 // After argument. The token should either be an equals sign or a comma or
605 // closing paren.
606 if (tok == "=") {
607 std::string default_val;
608 //Read an argument into default_val and set state to 2 if we're at
609 // the end; 0 if we hit a comma.
610 state = read_argument(default_val) ? 2 : 0;
611 args.add_arg(arg_name, default_val.c_str());
612 skip_spaces();
613 break;
614 }
615 if (tok == ",") {
616 // Take the identifier as an argument with no default value.
617 args.add_arg(arg_name, nullptr);
618 state = 0;
619 skip_spaces();
620 break;
621 }
622 if (tok == ")") {
623 // As with comma, but set state to 2 (end of args)
624 args.add_arg(arg_name, nullptr);
625 state = 2;
626 skip_spaces();
627 break;
628 }
629 log_error("Trailing contents after identifier in macro argument `%s': "
630 "expected '=', ',' or ')'.\n",
631 arg_name.c_str());
632
633 default:
634 // The only FSM states are 0-2 and we dealt with 2 at the start of the loop.
635 log_assert(false);
636 }
637 }
638
639 return std::make_pair(newline_count, args);
640 }
641
642 // Read a `define preprocessor directive. This is called just after reading the token containing
643 // "`define".
644 static void
645 read_define(const std::string &filename,
646 define_map_t &defines_map,
647 define_map_t &global_defines_cache)
648 {
649 std::string name, value;
650 arg_map_t args;
651
652 skip_spaces();
653 name = next_token(true);
654
655 bool here_doc_mode = false;
656 int newline_count = 0;
657
658 // The FSM state starts at 0. If it sees space (or enters here_doc_mode), it assumes this is
659 // a macro without formal arguments and jumps to state 1.
660 //
661 // In state 0, if it sees an opening parenthesis, it assumes this is a macro with formal
662 // arguments. It reads the arguments with read_define_args() and then jumps to state 2.
663 //
664 // In states 1 or 2, the FSM reads tokens to the end of line (or end of here_doc): this is
665 // the body of the macro definition.
666 int state = 0;
667
668 if (skip_spaces() != "")
669 state = 1;
670
671 for (;;) {
672 std::string tok = next_token();
673 if (tok.empty())
674 break;
675
676 // printf("define-tok: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE");
677
678 if (tok == "\"\"\"") {
679 here_doc_mode = !here_doc_mode;
680 continue;
681 }
682
683 if (state == 0 && tok == "(") {
684 auto pr = read_define_args();
685 newline_count += pr.first;
686 args = pr.second;
687
688 state = 2;
689 continue;
690 }
691
692 // This token isn't an opening parenthesis immediately following the macro name, so
693 // it's presumably at or after the start of the macro body. If state isn't already 2
694 // (which would mean we'd parsed an argument list), set it to 1.
695 if (state == 0) {
696 state = 1;
697 }
698
699 if (tok == "\n") {
700 if (here_doc_mode) {
701 value += " ";
702 newline_count++;
703 } else {
704 return_char('\n');
705 break;
706 }
707 continue;
708 }
709
710 if (tok == "\\") {
711 char ch = next_char();
712 if (ch == '\n') {
713 value += " ";
714 newline_count++;
715 } else {
716 value += std::string("\\");
717 return_char(ch);
718 }
719 continue;
720 }
721
722 // Is this token the name of a macro argument? If so, replace it with a magic symbol
723 // that we'll replace with the argument value.
724 int arg_pos;
725 if (args.find(tok, &arg_pos)) {
726 value += '`' + args.str_token(name, arg_pos);
727 continue;
728 }
729
730 // This token is nothing special. Insert it verbatim into the macro body.
731 value += tok;
732 }
733
734 // Append some newlines so that we don't mess up line counts in error messages.
735 while (newline_count-- > 0)
736 return_char('\n');
737
738 if (strchr("abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789", name[0])) {
739 // printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str());
740 defines_map.add(name, value, (state == 2) ? &args : nullptr);
741 global_defines_cache.add(name, value, (state == 2) ? &args : nullptr);
742 } else {
743 log_file_error(filename, 0, "Invalid name for macro definition: >>%s<<.\n", name.c_str());
744 }
745 }
746
747 std::string
748 frontend_verilog_preproc(std::istream &f,
749 std::string filename,
750 const define_map_t &pre_defines,
751 define_map_t &global_defines_cache,
752 const std::list<std::string> &include_dirs)
753 {
754 define_map_t defines;
755 defines.merge(pre_defines);
756 defines.merge(global_defines_cache);
757
758 macro_arg_stack_t macro_arg_stack;
759 std::vector<std::string> filename_stack;
760 // We are inside pass_level levels of satisfied ifdefs, and then within
761 // fail_level levels of unsatisfied ifdefs. The unsatisfied ones are
762 // always within satisfied ones — even if some condition within is true,
763 // the parent condition failing renders it moot.
764 int ifdef_fail_level = 0;
765 int ifdef_pass_level = 0;
766 // For the outermost unsatisfied ifdef, true iff that ifdef already
767 // had a satisfied branch, and further elsif/else branches should be
768 // considered unsatisfied even if the condition is true.
769 // Meaningless if ifdef_fail_level == 0.
770 bool ifdef_already_satisfied = false;
771
772 output_code.clear();
773 input_buffer.clear();
774 input_buffer_charp = 0;
775
776 input_file(f, filename);
777
778 while (!input_buffer.empty())
779 {
780 std::string tok = next_token();
781 // printf("token: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE");
782
783 if (tok == "`endif") {
784 if (ifdef_fail_level > 0)
785 ifdef_fail_level--;
786 else if (ifdef_pass_level > 0)
787 ifdef_pass_level--;
788 else
789 log_error("Found %s outside of macro conditional branch!\n", tok.c_str());
790 continue;
791 }
792
793 if (tok == "`else") {
794 if (ifdef_fail_level == 0) {
795 if (ifdef_pass_level == 0)
796 log_error("Found %s outside of macro conditional branch!\n", tok.c_str());
797 ifdef_pass_level--;
798 ifdef_fail_level = 1;
799 ifdef_already_satisfied = true;
800 } else if (ifdef_fail_level == 1 && !ifdef_already_satisfied) {
801 ifdef_fail_level = 0;
802 ifdef_pass_level++;
803 ifdef_already_satisfied = true;
804 }
805 continue;
806 }
807
808 if (tok == "`elsif") {
809 skip_spaces();
810 std::string name = next_token(true);
811 if (ifdef_fail_level == 0) {
812 if (ifdef_pass_level == 0)
813 log_error("Found %s outside of macro conditional branch!\n", tok.c_str());
814 ifdef_pass_level--;
815 ifdef_fail_level = 1;
816 ifdef_already_satisfied = true;
817 } else if (ifdef_fail_level == 1 && !ifdef_already_satisfied && defines.find(name)) {
818 ifdef_fail_level = 0;
819 ifdef_pass_level++;
820 ifdef_already_satisfied = true;
821 }
822 continue;
823 }
824
825 if (tok == "`ifdef") {
826 skip_spaces();
827 std::string name = next_token(true);
828 if (ifdef_fail_level > 0 || !defines.find(name)) {
829 ifdef_fail_level++;
830 } else {
831 ifdef_pass_level++;
832 ifdef_already_satisfied = true;
833 }
834 if (ifdef_fail_level == 1)
835 ifdef_already_satisfied = false;
836 continue;
837 }
838
839 if (tok == "`ifndef") {
840 skip_spaces();
841 std::string name = next_token(true);
842 if (ifdef_fail_level > 0 || defines.find(name)) {
843 ifdef_fail_level++;
844 } else {
845 ifdef_pass_level++;
846 ifdef_already_satisfied = true;
847 }
848 if (ifdef_fail_level == 1)
849 ifdef_already_satisfied = false;
850 continue;
851 }
852
853 if (ifdef_fail_level > 0) {
854 if (tok == "\n")
855 output_code.push_back(tok);
856 continue;
857 }
858
859 if (tok == "`include") {
860 skip_spaces();
861 std::string fn = next_token(true);
862 while (try_expand_macro(defines, macro_arg_stack, fn)) {
863 fn = next_token();
864 }
865 while (1) {
866 size_t pos = fn.find('"');
867 if (pos == std::string::npos)
868 break;
869 if (pos == 0)
870 fn = fn.substr(1);
871 else
872 fn = fn.substr(0, pos) + fn.substr(pos+1);
873 }
874 std::ifstream ff;
875 ff.clear();
876 std::string fixed_fn = fn;
877 ff.open(fixed_fn.c_str());
878
879 bool filename_path_sep_found;
880 bool fn_relative;
881 #ifdef _WIN32
882 // Both forward and backslash are acceptable separators on Windows.
883 filename_path_sep_found = (filename.find_first_of("/\\") != std::string::npos);
884 // Easier just to invert the check for an absolute path (e.g. C:\ or C:/)
885 fn_relative = !(fn[1] == ':' && (fn[2] == '/' || fn[2] == '\\'));
886 #else
887 filename_path_sep_found = (filename.find('/') != std::string::npos);
888 fn_relative = (fn[0] != '/');
889 #endif
890
891 if (ff.fail() && fn.size() > 0 && fn_relative && filename_path_sep_found) {
892 // if the include file was not found, it is not given with an absolute path, and the
893 // currently read file is given with a path, then try again relative to its directory
894 ff.clear();
895 #ifdef _WIN32
896 fixed_fn = filename.substr(0, filename.find_last_of("/\\")+1) + fn;
897 #else
898 fixed_fn = filename.substr(0, filename.rfind('/')+1) + fn;
899 #endif
900 ff.open(fixed_fn);
901 }
902 if (ff.fail() && fn.size() > 0 && fn_relative) {
903 // if the include file was not found and it is not given with an absolute path, then
904 // search it in the include path
905 for (auto incdir : include_dirs) {
906 ff.clear();
907 fixed_fn = incdir + '/' + fn;
908 ff.open(fixed_fn);
909 if (!ff.fail()) break;
910 }
911 }
912 if (ff.fail()) {
913 output_code.push_back("`file_notfound " + fn);
914 } else {
915 input_file(ff, fixed_fn);
916 yosys_input_files.insert(fixed_fn);
917 }
918 continue;
919 }
920
921 if (tok == "`file_push") {
922 skip_spaces();
923 std::string fn = next_token(true);
924 if (!fn.empty() && fn.front() == '"' && fn.back() == '"')
925 fn = fn.substr(1, fn.size()-2);
926 output_code.push_back(tok + " \"" + fn + "\"");
927 filename_stack.push_back(filename);
928 filename = fn;
929 continue;
930 }
931
932 if (tok == "`file_pop") {
933 output_code.push_back(tok);
934 filename = filename_stack.back();
935 filename_stack.pop_back();
936 continue;
937 }
938
939 if (tok == "`define") {
940 read_define(filename, defines, global_defines_cache);
941 continue;
942 }
943
944 if (tok == "`undef") {
945 std::string name;
946 skip_spaces();
947 name = next_token(true);
948 // printf("undef: >>%s<<\n", name.c_str());
949 defines.erase(name);
950 global_defines_cache.erase(name);
951 continue;
952 }
953
954 if (tok == "`timescale") {
955 skip_spaces();
956 while (!tok.empty() && tok != "\n")
957 tok = next_token(true);
958 if (tok == "\n")
959 return_char('\n');
960 continue;
961 }
962
963 if (tok == "`resetall") {
964 defines.clear();
965 global_defines_cache.clear();
966 continue;
967 }
968
969 if (tok == "`__restore_macro_arg") {
970 restore_macro_arg(defines, macro_arg_stack);
971 continue;
972 }
973
974 if (try_expand_macro(defines, macro_arg_stack, tok))
975 continue;
976
977 output_code.push_back(tok);
978 }
979
980 if (ifdef_fail_level > 0 || ifdef_pass_level > 0) {
981 log_error("Unterminated preprocessor conditional!\n");
982 }
983
984 std::string output;
985 for (auto &str : output_code)
986 output += str;
987
988 output_code.clear();
989 input_buffer.clear();
990 input_buffer_charp = 0;
991
992 return output;
993 }
994
995 YOSYS_NAMESPACE_END