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