It depends...
Will you need to:
- Produce many similar instances either across languages?
- Slight variations within the same language?
- Handle a complex grammar (such as a scripting language)?
Code-Generation will look good because its write-once, declarative, reproducible, and the tooling can assist in generating correct grammars.
Unfortunately most generators do not provide the semantic mappings, and even when they do, two applications may have different internal models and hence different mappings. If you do go down this route most of the heavy lifting is done for you in terms of syntax and assembly. You will however need to encode the compositional semantics for whatever model the configuration is assembling.
The other downsides are that generators produce unintelligible code, require an extra tool in the build chain, and have uncanny traps for the unfamiliar such as infinite regress.
Will you need to:
- Handle
Key:Value style configuration?
- provide some semblance of human readability?
- potential need internationalisation?
Prefer to use a stock off the shelf configuration file language. These languages often come with easy to use and reliable object serial, and dom style parsers native to your language. These handle pesky details of multi-language encodings, escapes, and other parsing woes. The only drawback is that you still need to comprehend that object structure and translate it into your own domain objects. Don't be tempted to just use the parsed objects directly, that way leads to high coupling.
Alternately
- The parser-generator tooling is inappropriate or imposes too many restrictions.
- The off the shelf config languages are inappropriate
- The language being parsed is a murky mess without obvious rules, yet...
Roll your own parser, its not terribly difficult.
Rules of thumb:
- keep lexing, parsing, and assembling separated by clean interfaces.
- do not throw to communicate failure to parse, this is an expected outcome.
- on an error always report in the output/on return diagnostics: current parse tree and assembled data, line, column, what was not found, what was found instead, and perhaps advice on how to fix it.
- always report diagnostics reported by a sub-parse, even if successful, this allows warnings to be communicated.
- always have a "test" assembly implementation that returns a collection of the values it was given to assemble, with the context. This allows you to easily test lexing and parsing, and to produce a validator program with useful diagnostics.
but I didn't know the Consequences of each choicesThere's no shortcuts to the heaven. Why don't make a proof of concept? Experiencing the pros and cons yourself is way more useful and valuable for you than just believing strangers on the internet.