Adding support for string macros and macros with arguments after include
authorcombinatorylogic <combinatorylogic@users.noreply.github.com>
Thu, 21 Sep 2017 17:25:02 +0000 (18:25 +0100)
committercombinatorylogic <combinatorylogic@users.noreply.github.com>
Thu, 21 Sep 2017 17:25:02 +0000 (18:25 +0100)
frontends/verilog/preproc.cc

index cf220fef908e2761d27799653c8d23c1b2eecc94..67a6d18eaff4cf81a4b27034560f32a4b8cf68f0 100644 (file)
@@ -182,15 +182,19 @@ static std::string next_token(bool pass_newline = false)
        {
                const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789";
                if (ch == '`' || strchr(ok, ch) != NULL)
-                       while ((ch = next_char()) != 0) {
-                               if (strchr(ok, ch) == NULL) {
-                                       return_char(ch);
-                                       break;
-                               }
+               {
+                       ch = next_char();
+                       if (ch == '"') {
                                token += ch;
-                       }
+                       } else do {
+                                       if (strchr(ok, ch) == NULL) {
+                                               return_char(ch);
+                                               break;
+                                       }
+                                       token += ch;
+                               } while ((ch = next_char()) != 0);
+               }
        }
-
        return token;
 }
 
@@ -210,6 +214,59 @@ static void input_file(std::istream &f, std::string filename)
        input_buffer.insert(it, "\n`file_pop\n");
 }
 
+
+static bool try_expand_macro(std::set<std::string> &defines_with_args,
+                            std::map<std::string, std::string> &defines_map,
+                            std::string &tok
+                                   )
+{
+       if (tok == "`\"") {
+               std::string literal("\"");
+               // Expand string literal
+               while (!input_buffer.empty()) {
+                       std::string ntok = next_token();
+                       if (ntok == "`\"") {
+                               insert_input(literal+"\"");
+                               return true;
+                       } else if (!try_expand_macro(defines_with_args, defines_map, ntok)) {
+                                       literal += ntok;
+                       }
+               }
+               return false; // error - unmatched `"
+       } else if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) {
+                       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(false);
+                       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 (int i = 0; i < GetSize(args); 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]);
+                       return true;
+       } else return false;
+}
+
 std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> &pre_defines_map,
                dict<std::string, std::pair<std::string, bool>> &global_defines_cache, const std::list<std::string> &include_dirs)
 {
@@ -293,8 +350,9 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
                if (tok == "`include") {
                        skip_spaces();
                        std::string fn = next_token(true);
-                       while (fn.size() > 1 && fn[0] == '`' && defines_map.count(fn.substr(1)) > 0)
-                               fn = defines_map.at(fn.substr(1));
+                       while(try_expand_macro(defines_with_args, defines_map, fn)) {
+                               fn = next_token();
+                       }
                        while (1) {
                                size_t pos = fn.find('"');
                                if (pos == std::string::npos)
@@ -445,39 +503,9 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
                        continue;
                }
 
-               if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) {
-                       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(false);
-                       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 (int i = 0; i < GetSize(args); 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]);
+               if (try_expand_macro(defines_with_args, defines_map, tok))
                        continue;
-               }
-
+               
                output_code.push_back(tok);
        }