Skip to content
12 changes: 11 additions & 1 deletion doc/cpp-target.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ This example assumes your grammar contains a parser rule named `key` for which t

There are a couple of things that only the C++ ANTLR target has to deal with. They are described here.

### Build Aspects
### Code Generation Aspects
The code generation (by running the ANTLR4 jar) allows to specify 2 values you might find useful for better integration of the generated files into your application (both are optional):

* A **namespace**: use the **`-package`** parameter to specify the namespace you want.
Expand All @@ -102,6 +102,16 @@ In order to create a static lib in Visual Studio define the `ANTLR4CPP_STATIC` m

For gcc and clang it is possible to use the `-fvisibility=hidden` setting to hide all symbols except those that are made default-visible (which has been defined for all public classes in the runtime).

### Compile Aspects

When compiling generated files, you can configure a compile option according to your needs (also optional):

* A **thread local DFA macro**: Add `-DANTLR4_USE_THREAD_LOCAL_CACHE=1` to the compilation options
will enable using thread local DFA cache (disabled by default), after that, each thread uses its own DFA.
This will increase memory usage to store thread local DFAs and redundant computation to build thread local DFAs (not too much).
The benefit is that it can improve the concurrent performance running with multiple threads.
In other words, when you find your concurent throughput is not high enough, you should consider turning on this option.

### Memory Management
Since C++ has no built-in memory management we need to take extra care. For that we rely mostly on smart pointers, which however might cause time penalties or memory side effects (like cyclic references) if not used with care. Currently however the memory household looks very stable. Generally, when you see a raw pointer in code consider this as being managed elsewhere. You should never try to manage such a pointer (delete, assign to smart pointer etc.).

Expand Down
26 changes: 26 additions & 0 deletions tool/resources/org/antlr/v4/tool/templates/codegen/Cpp/Cpp.stg
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,19 @@ struct <lexer.name; format = "cap">StaticData final {
};

::antlr4::internal::OnceFlag <lexer.grammarName; format = "lower">LexerOnceFlag;
#if ANTLR4_USE_THREAD_LOCAL_CACHE
static thread_local
#endif
<lexer.name; format = "cap">StaticData *<lexer.grammarName; format = "lower">LexerStaticData = nullptr;

void <lexer.grammarName; format = "lower">LexerInitialize() {
#if ANTLR4_USE_THREAD_LOCAL_CACHE
if (<lexer.grammarName; format = "lower">LexerStaticData != nullptr) {
return;
}
#else
assert(<lexer.grammarName; format = "lower">LexerStaticData == nullptr);
#endif
auto staticData = std::make_unique\<<lexer.name; format = "cap">StaticData>(
std::vector\<std::string>{
<lexer.ruleNames: {r | "<r>"}; separator = ", ", wrap, anchor>
Expand Down Expand Up @@ -238,7 +247,11 @@ bool <lexer.name>::sempred(RuleContext *context, size_t ruleIndex, size_t predic
<sempredFuncs.values; separator="\n">

void <lexer.name>::initialize() {
#if ANTLR4_USE_THREAD_LOCAL_CACHE
<lexer.grammarName; format = "lower">LexerInitialize();
#else
::antlr4::internal::call_once(<lexer.grammarName; format = "lower">LexerOnceFlag, <lexer.grammarName; format = "lower">LexerInitialize);
#endif
}
>>

Expand Down Expand Up @@ -364,10 +377,19 @@ struct <parser.name; format = "cap">StaticData final {
};

::antlr4::internal::OnceFlag <parser.grammarName; format = "lower">ParserOnceFlag;
#if ANTLR4_USE_THREAD_LOCAL_CACHE
static thread_local
#endif
<parser.name; format = "cap">StaticData *<parser.grammarName; format = "lower">ParserStaticData = nullptr;

void <parser.grammarName; format = "lower">ParserInitialize() {
#if ANTLR4_USE_THREAD_LOCAL_CACHE
if (<parser.grammarName; format = "lower">ParserStaticData != nullptr) {
return;
}
#else
assert(<parser.grammarName; format = "lower">ParserStaticData == nullptr);
#endif
auto staticData = std::make_unique\<<parser.name; format = "cap">StaticData>(
std::vector\<std::string>{
<parser.ruleNames: {r | "<r>"}; separator = ", ", wrap, anchor>
Expand Down Expand Up @@ -435,7 +457,11 @@ bool <parser.name>::sempred(RuleContext *context, size_t ruleIndex, size_t predi
<sempredFuncs.values; separator="\n"><endif>

void <parser.name>::initialize() {
#if ANTLR4_USE_THREAD_LOCAL_CACHE
<parser.grammarName; format = "lower">ParserInitialize();
#else
::antlr4::internal::call_once(<parser.grammarName; format = "lower">ParserOnceFlag, <parser.grammarName; format = "lower">ParserInitialize);
#endif
}
>>

Expand Down