diff options
Diffstat (limited to 'frontends/verilog/preproc.cc')
-rw-r--r-- | frontends/verilog/preproc.cc | 122 |
1 files changed, 97 insertions, 25 deletions
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 8d435d940..5cfa0f24b 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -76,8 +76,9 @@ static char next_char() return ch == '\r' ? next_char() : ch; } -static void skip_spaces() +static std::string skip_spaces() { + std::string spaces; while (1) { char ch = next_char(); if (ch == 0) @@ -86,7 +87,9 @@ static void skip_spaces() return_char(ch); break; } + spaces += ch; } + return spaces; } static std::string next_token(bool pass_newline = false) @@ -170,13 +173,14 @@ static std::string next_token(bool pass_newline = false) else { const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789"; - while ((ch = next_char()) != 0) { - if (strchr(ok, ch) == NULL) { - return_char(ch); - break; + if (ch == '`' || strchr(ok, ch) != NULL) + while ((ch = next_char()) != 0) { + if (strchr(ok, ch) == NULL) { + return_char(ch); + break; + } + token += ch; } - token += ch; - } } return token; @@ -200,8 +204,10 @@ static void input_file(FILE *f, std::string filename) std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs) { + std::set<std::string> defines_with_args; std::map<std::string, std::string> defines_map(pre_defines_map); int ifdef_fail_level = 0; + bool in_elseif = false; output_code.clear(); input_buffer.clear(); @@ -218,17 +224,29 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m if (tok == "`endif") { if (ifdef_fail_level > 0) ifdef_fail_level--; + if (ifdef_fail_level == 0) + in_elseif = false; continue; } if (tok == "`else") { if (ifdef_fail_level == 0) ifdef_fail_level = 1; - else if (ifdef_fail_level == 1) + else if (ifdef_fail_level == 1 && !in_elseif) ifdef_fail_level = 0; continue; } + if (tok == "`elsif") { + skip_spaces(); + std::string name = next_token(true); + if (ifdef_fail_level == 0) + ifdef_fail_level = 1, in_elseif = true; + else if (ifdef_fail_level == 1 && defines_map.count(name) != 0) + ifdef_fail_level = 0, in_elseif = true; + continue; + } + if (tok == "`ifdef") { skip_spaces(); std::string name = next_token(true); @@ -289,32 +307,58 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m if (tok == "`define") { std::string name, value; + std::map<std::string, int> args; skip_spaces(); name = next_token(true); - skip_spaces(); int newline_count = 0; + int state = 0; + if (skip_spaces() != "") + state = 3; while (!tok.empty()) { tok = next_token(); - if (tok == "\n") { - return_char('\n'); - break; - } - if (tok == "\\") { - char ch = next_char(); - if (ch == '\n') { - value += " "; - newline_count++; - } else { - value += std::string("\\"); - return_char(ch); - } + if (state == 0 && tok == "(") { + state = 1; + skip_spaces(); } else - value += tok; + if (state == 1) { + if (tok == ")") + state = 2; + else if (tok != ",") { + int arg_idx = args.size()+1; + args[tok] = arg_idx; + } + skip_spaces(); + } else { + if (state != 2) + state = 3; + if (tok == "\n") { + return_char('\n'); + break; + } + if (tok == "\\") { + char ch = next_char(); + if (ch == '\n') { + value += " "; + newline_count++; + } else { + value += std::string("\\"); + return_char(ch); + } + } else + if (args.count(tok) > 0) + value += stringf("`macro_%s_arg%d", name.c_str(), args.at(tok)); + else + value += tok; + } } while (newline_count-- > 0) return_char('\n'); // printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str()); defines_map[name] = value; + if (state == 2) + defines_with_args.insert(name); + else + defines_with_args.erase(name); continue; } @@ -324,6 +368,7 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m name = next_token(true); // printf("undef: >>%s<<\n", name.c_str()); defines_map.erase(name); + defines_with_args.erase(name); continue; } @@ -338,8 +383,35 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m } if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) { - // printf("expand: >>%s<< -> >>%s<<\n", tok.c_str(), defines_map[tok.substr(1)].c_str()); - insert_input(defines_map[tok.substr(1)]); + std::string name = tok.substr(1); + // printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str()); + std::string skipped_spaces = skip_spaces(); + tok = next_token(true); + if (tok == "(" && defines_with_args.count(name) > 0) { + int level = 1; + std::vector<std::string> args; + args.push_back(std::string()); + while (1) + { + tok = next_token(true); + if (tok == ")" || tok == "}" || tok == "]") + level--; + if (level == 0) + break; + if (level == 1 && tok == ",") + args.push_back(std::string()); + else + args.back() += tok; + if (tok == "(" || tok == "{" || tok == "[") + level++; + } + for (size_t i = 0; i < args.size(); i++) + defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i]; + } else { + insert_input(tok); + insert_input(skipped_spaces); + } + insert_input(defines_map[name]); continue; } |