3

I want to wrap every string literal in my project with a macro. I want to make sure every string literal in my project is wrapped with a macro, and have some external tool help provide me the location in which there's a string literal not wrapped in a macro.

Is there any way I could use Clang Plugins to ensure that every string literal is wrapped inside macro?

Cases I want to handle:

  1. #define MY_ASSERT(Y) {if(!(Y)) throw Exception(#Y); }
    

    The #Y should be warned as unwrapped string literal.

  2. "a" "b" "c"
    

    It will require that the whole thing will be inside a macro, like this:

    MY_STR("a" "b" "c")
    

How could I do that with Clang plugin, or is there an other way in general to do it?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Curve25519
  • 654
  • 5
  • 17
  • 3
    *I want to wrap every string literal in my project with a macro* – I'm just curious: what for? – Swordfish Feb 25 '19 at 13:55
  • 1
    @Swordfish - Well, one reason that pops to mind https://stackoverflow.com/questions/15498070/what-does-t-stands-for-in-a-cstring – StoryTeller - Unslander Monica Feb 25 '19 at 13:58
  • @Swordfish I want to be able to replace some strings with their translation in various languages. Found it much easier to wrap every string with macro that will sometimes will translate, and sometimes will help us provide a list of the used strings in the project that needs to be translated. – Curve25519 Feb 25 '19 at 14:01
  • Use a internationalization framework?? Boost.Locale for eg. – Swordfish Feb 25 '19 at 14:18
  • AFAIK even if you use Boost.Locale you still need to call a function, the strings don't magically translate. I want every string to be translated, with no exception. ?? – Curve25519 Feb 25 '19 at 14:26
  • @TalShalti not everything that is a function call in c++ has to be a function call in compiled code. Translations could be solved using `constexpr`, so a `mylib::translate("my string")` would be replaced by `"my translated string"` in the compiling step. I know this does not answer your question, it should just be an information for you that macros are not required for that. – t.niese Feb 27 '19 at 13:39
  • @t.niese Thanks for your comment. I understand what you're saying, and I'm well aware of that. I just figured that if the string literals in my code are wrapped in macro call anything else I would want to do wouldn't require a Clang plugin. Such as discovery or any other function. – Curve25519 Feb 27 '19 at 14:03

1 Answers1

2

You could do that with the DMS Software Reengineering Toolkit and its C++ front end.

DMS can read source code according it the explicit grammar definition of C++ (handles C++17 in GCC and MS dialects), builds an AST, applies rewrite rules supplied to modify the tree, and then prettyprints the AST back to source text, preserving comments, text alignments, number radixes, etc.

To do this, you need just one DMS rule (see DMS Rewrite Rules for details):

rule wrap_string_in_macro(s:string_literal):primary_expression->primary_expression
 = "\s" -> " my_macro_name(\s) ";

The nonterminal string_literal covers the wide variety of C++ strings (8bit, ISO, wide, raw, sequence of strings, ...) so you don't have to worry about them, this rule will pick them up. But your macro might need to worry about those. So you could arguably write a larger set of rules so you can specialize the macro call:

rule wrap_ISO_string_in_macro(s:ISO_STRING_LITERAL):primary_expression->primary_expression
 = "\s" -> " my_macro_name_for_ISO_string(\s) ";

rule wrap_ISO_string_in_macro(s:WIDE_STRING_LITERAL):primary_expression->primary_expression
 = "\s" -> " my_macro_name_for_wide_string(\s) ";

...

These rules will pick up individual strings, but that leaves the problem of handling sequences of strings:

rule wrap_ISO_string_list_in_macro(seq: string_literal_list,s:ISO_STRING_LITERAL):primary_expression->primary_expression
 = " \string_literal_list \s" -> " my_macro_name_for_ISO_string_list(\s) ";

...
Ira Baxter
  • 93,541
  • 22
  • 172
  • 341