Code generation from template file - c++

I have written a template file which is as follows
Hello ${Name}
I like ${food}
I wanted to write a c++ code which generates the following code using the template file as reference
Hello John
I like Pasta
I like Pasta
I like Pasta
Is there a way to do this in C++? I came across "ctemplate", but I was not convinced.
The application I am developing is cross-platform.
( I wanted to do something like string template in c#)

I've written a template expansion 'engine' using Boost Spirit before:
Compiling a simple parser with Boost.Spirit
It's really versatile
supports nested expansions
supports recursive expansions
supports dynamic expansions (e.g. if you want a variable to be expanded with a different value depending on the context)
I've just adapted it to your question's macro syntax. See it Live On Coliru
Update
Okay, since performance appears to be the primary goal, here's a highly optimized expansion engine, in a benchmark:
#include <string>
#include <sstream>
#include <map>
#include <boost/utility/string_ref.hpp>
template <typename Range>
std::string expand(Range const& key)
{
if (key == "Name")
return "John";
if (key == "food")
return "Pasta";
return "??";
}
#include <iostream>
int main()
{
static const std::string msg_template =
"Hello ${Name}\n"
"I like ${food}\n"
;
std::ostringstream builder;
builder.str().reserve(1024); // reserve ample room, not crucial since we reuse it anyways
for (size_t iterations = 1ul << 22; iterations; --iterations)
{
builder.str("");
std::ostreambuf_iterator<char> out(builder);
for(auto f(msg_template.begin()), l(msg_template.end()); f != l;)
{
switch(*f)
{
case '$' :
{
if (++f==l || *f!='{')
{
*out++ = '$';
break;
}
else
{
auto s = ++f;
size_t n = 0;
while (f!=l && *f != '}')
++f, ++n;
// key is [s,f] now
builder << expand(boost::string_ref(&*s, n));
if (f!=l)
++f; // skip '}'
}
}
default:
*out++ = *f++;
}
}
// to make it slow, uncomment:
// std::cout << builder.str();
}
std::cout << builder.str();
}
It runs 2^22 (4,194,304) iterations in ~0.775s
See it Live On Coliru too (where it runs in ~1.8s).

The standard libraries have excellent facilities for everyday regex parsing (which is what you need), take a look at the docs here.
You need to learn about regex if you've never heard of it - this is at least one place outlining the details.
Alternately if you are concerned with performance and your task is literally as simple as you describe then writing your own parser should be very straight forward using two streams and seeking forward for the ${ escape sequence while copying across to the output stream substituting as needed.

Related

How to count assignment operators in a text file?

My task is to create a program in C ++ that processes a text file in sequential mode. The data must be read from the file one line at a time. Do not back up the entire contents of the file to RAM. The text file contains syntactically correct C++ code and I have to count how many assignment operators are there.
The only thing I could think of was making a function that searches for patterns and then counts how many times they appear. I insert every assignment operator as a pattern and then sum all the counts together. But this does not work because if I insert the pattern "=" many operators such as "%=" or "+=" also get counted in. And even operators like "!=" or "==" get counted, but they shouldn't because they are comparison operators.
My code gives the answer 7 but the real answer should be 5.
#include <iostream>
#include <fstream>
using namespace std;
int patternCounting(string pattern, string text){
int x = pattern.size();
int y = text.size();
int rez = 0;
for(int i=0; i<=y-x; i++){
int j;
for(j=0; j<x; j++)
if(text[i+j] !=pattern[j]) break;
if(j==x) rez++;
}
return rez;
}
int main()
{
fstream file ("test.txt", ios::in);
string rinda;
int skaits=0;
if(!file){cout<<"Nav faila!"<<endl; return 47;}
while(file.good()){
getline(file, rinda);
skaits+=patternCounting("=",rinda);
skaits+=patternCounting("+=",rinda);
skaits+=patternCounting("*=",rinda);
skaits+=patternCounting("-=",rinda);
skaits+=patternCounting("/=",rinda);
skaits+=patternCounting("%=",rinda);
}
cout<<skaits<<endl;
return 0;
}
Contents of the text file:
#include <iostream>
using namespace std;
int main()
{
int z=3;
int x=4;
for(int i=3; i<3; i++){
int f+=x;
float g%=3;
}
}
Note that as a torture test, the following code has 0 assignments on older C++ standards and one on newer ones, due to the abolition of trigraphs.
// = Torture test
int a = 0; int b = 1;
int main()
{
// The next line is part of this comment until C++17 ??/
a = b;
struct S
{
virtual void foo() = 0;
void foo(int, int x = 1);
S& operator=(const S&) = delete;
int m = '==';
char c = '=';
};
const char* s = [=]{return "=";}();
sizeof(a = b);
decltype(a = b) c(a);
}
There are multiple issues with the code.
The first, rather mundane issue, is your handling of file reading. A loop such as while (file.good()) … is virtually always an error: you need to test the return value of getline instead!
std::string line;
while (getline(file, line)) {
// Process `line` here.
}
Next, your patternCounting function fundamentally won’t work since it doesn’t account for comments and strings (nor any of C++’s other peculiarities, but these seem to be out of scope for your assignment). It also doesn’t really make sense to count different assignment operators separately.
The third issue is that your test case misses lots of edge cases (and is invalid C++). Here’s a better test case that (I think) exercises all interesting edge cases from your assignment:
int main()
{
int z=3; // 1
int x=4; // 2
// comment with = in it
"string with = in it";
float f = 3; // 3
f = f /= 4; // 4, 5
for (int i=3; i != 3; i++) { // 6
int f=x += z; // 7, 8
bool g=3 == 4; // 9
}
}
I’ve annotated each line with a comment indicating up to how many occurrences we should have counted by now.
Now that we have a test case, we can start implementing the actual counting logic. Note that, for readability, function names generally follow the pattern “verb subject”. So instead of patternCounting a better function name would be countPattern. But we won’t count arbitrary patterns, we will count assignments. So I’ll use countAssignments (or, using my preferred C++ naming convention: count_assignments).
Now, what does this function need to do?
It needs to count assignments (incl. initialisations), duh.
It needs to discount occurrences of = that are not assignments:
inside strings
inside comments
inside comparison operators
Without a dedicated C++ parser, that’s a rather tall order! You will need to implement a rudimentary lexical analyser (short: lexer) for C++.
First off, you will need to represent each of the situations we care about with its own state:
enum class state {
start,
comment,
string,
comparison
};
With this in hand, we can start writing the outline of the count_assignments function:
int count_assignments(std::string const& str) {
auto count = 0;
auto state = state::start;
auto prev_char = '\0';
for (auto c : str) {
switch (state) {
case state::start:
break;
case state::comment:
break;
case state::string:
break;
case state::comparison:
break;
}
prev_char = c;
}
// Useful for debugging:
// std::cerr << count << "\t" << str << "\n";
return count;
}
As you can see, we iterate over the characters of the string (for (c : str)). Next, we handle each state we could be currently in.
The prev_char is necessary because some of our lexical tokens are more than one character in length (e.g. comments start by //, but /= is an assignment that we want to count!). This is a bit of a hack — for a real lexer I would split such cases into distinct states.
So much for the function skeleton. Now we need to implement the actual logic — i.e. we need to decide what to do depending on the current (and previous) character and the current state.
To get you started, here’s the case state::start:
switch (c) {
case '=':
++count;
state = state::comparison;
break;
case '<': case '>': case '!':
state = state::comparison;
break;
case '"' :
state = state::string;
break;
case '/' :
if (prev_char == '/') {
state = state::comment;
}
break;
}
Be very careful: the above will over-count the comparison ==, so we will need to adjust that count once we’re inside case state::comparison and see that the current and previous character are both =.
I’ll let you take a stab at the rest of the implementation.
Note that, unlike your initial attempt, this implementation doesn’t distinguish the separate assignment operators (=, +=, etc.) because there’s no need to do so: they’re all counted automatically.
The clang compiler has a feature to dump the syntax tree (also called AST). If you have syntactically correct C++ code (which you don't have), you can count the number of assignment operators for example with the following command line (on a unixoid OS):
clang++ -Xclang -ast-dump -c my_cpp_file.cpp | egrep "BinaryOperator.*'='" | wc -l
Note however that this will only match real assigments, not copy initializations, which also can use the = character, but are something syntactically different (for example an overloaded = operator is not called in that case).
If you want to count the compound assignments and/or the copy initializations as well, you can try to look for the corresponding lines in the output AST and add them to the egrep search pattern.
In practice, your task is incredibly difficult.
Think for example of C++ raw string literals (you could have one spanning dozen of source lines, with arbitrary = inside them). Or of asm statements doing some addition....
Think also of increment operators like (for some declared int x;) a x++ (which is equivalent to x = x+1; for a simple variable, and semantically is an assignment operator - but not syntactically).
My suggestion: choose one open source C++ compiler. I happen to know GCC internals.
With GCC, you can write your own GCC plugin which would count the number of Gimple assignments.
Think also of Quine programs coded in C++...
NB: budget months of work.

How to cut off parts of a string, which every string in a collection has

My currently problem is the following:
I have a std::vector of full path names to files.
Now i want to cut off the common prefix of all string.
Example
If I have these 3 strings in the vector:
/home/user/foo.txt
/home/user/bar.txt
/home/baz.txt
I would like to cut off /home/ from every string in the vector.
Question
Is there any method to achieve this in general?
I want an algorithm that drops the common prefix of all string.
I currently only have an idea which solves this problem in O(n m) with n strings and m is the longest string length, by just going through every string with every other string char by char.
Is there a faster or more elegant way solving this?
This can be done entirely with std:: algorithms.
synopsis:
sort the input range if not already sorted. The first and last paths in the sorted range
will be the most dissimilar. Best case is O(N), worst case O(N + N.logN)
use std::mismatch to determine the larges common sequence between the
two most dissimilar paths [insignificant]
run through each path erasing the first COUNT characters where COUNT is the number of characters in the longest common sequence. O (N)
Best case time complexity: O(2N), worst case O(2N + N.logN) (can someone check that?)
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
std::string common_substring(const std::string& l, const std::string& r)
{
return std::string(l.begin(),
std::mismatch(l.begin(), l.end(),
r.begin(), r.end()).first);
}
std::string mutating_common_substring(std::vector<std::string>& range)
{
if (range.empty())
return std::string();
else
{
if (not std::is_sorted(range.begin(), range.end()))
std::sort(range.begin(), range.end());
return common_substring(range.front(), range.back());
}
}
std::vector<std::string> chop(std::vector<std::string> samples)
{
auto str = mutating_common_substring(samples);
for (auto& s : samples)
{
s.erase(s.begin(), std::next(s.begin(), str.size()));
}
return samples;
}
int main()
{
std::vector<std::string> samples = {
"/home/user/foo.txt",
"/home/user/bar.txt",
"/home/baz.txt"
};
samples = chop(std::move(samples));
for (auto& s : samples)
{
std::cout << s << std::endl;
}
}
expected:
baz.txt
user/bar.txt
user/foo.txt
Here's an alternate `common_substring' which does not require a sort. time complexity is in theory O(N) but whether it's faster in practice you'd have to check:
std::string common_substring(const std::vector<std::string>& range)
{
if (range.empty())
{
return {};
}
return std::accumulate(std::next(range.begin(), 1), range.end(), range.front(),
[](auto const& best, const auto& sample)
{
return common_substring(best, sample);
});
}
update:
Elegance aside, this is probably the fastest way since it avoids any memory allocations, performing all transformations in-place. For most architectures and sample sizes, this will matter more than any other performance consideration.
#include <iostream>
#include <vector>
#include <string>
void reduce_to_common(std::string& best, const std::string& sample)
{
best.erase(std::mismatch(best.begin(), best.end(),
sample.begin(), sample.end()).first,
best.end());
}
void remove_common_prefix(std::vector<std::string>& range)
{
if (range.size())
{
auto iter = range.begin();
auto best = *iter;
for ( ; ++iter != range.end() ; )
{
reduce_to_common(best, *iter);
}
auto prefix_length = best.size();
for (auto& s : range)
{
s.erase(s.begin(), std::next(s.begin(), prefix_length));
}
}
}
int main()
{
std::vector<std::string> samples = {
"/home/user/foo.txt",
"/home/user/bar.txt",
"/home/baz.txt"
};
remove_common_prefix(samples);
for (auto& s : samples)
{
std::cout << s << std::endl;
}
}
You have to search every string in the list. However you don't need to compare all the characters in every string. The common prefix can only get shorter, so you only need to compare with "the common prefix so far". I don't think this changes the big-O complexity - but it will make quite a difference to the actual speed.
Also, these look like file names. Are they sorted (bearing in mind that many filesystems tend to return things in sorted order)? If so, you only need to consider the first and last elements. If they are probably pr mostly ordered, then consider the common prefix of the first and last, and then iterate through all the other strings shortening the prefix further as necessary.
You just have to iterate over every string. You can only avoid iterating over the full length of strings needlessly by exploiting the fact, that the prefix can only shorten:
#include <iostream>
#include <string>
#include <vector>
std::string common_prefix(const std::vector<std::string> &ss) {
if (ss.empty())
// no prefix
return "";
std::string prefix = ss[0];
for (size_t i = 1; i < ss.size(); i++) {
size_t c = 0; // index after which the string differ
for (; c < prefix.length(); c++) {
if (prefix[c] != ss[i][c]) {
// strings differ from character c on
break;
}
}
if (c == 0)
// no common prefix
return "";
// the prefix is only up to character c-1, so resize prefix
prefix.resize(c);
}
return prefix;
}
void strip_common_prefix(std::vector<std::string> &ss) {
std::string prefix = common_prefix(ss);
if (prefix.empty())
// no common prefix, nothing to do
return;
// drop the common part, which are always the first prefix.length() characters
for (std::string &s: ss) {
s = s.substr(prefix.length());
}
}
int main()
{
std::vector<std::string> ss { "/home/user/foo.txt", "/home/user/bar.txt", "/home/baz.txt"};
strip_common_prefix(ss);
for (std::string &s: ss)
std::cout << s << "\n";
}
Drawing from the hints of Martin Bonner's answer, you may implement a more efficient algorithm if you have more prior knowledge on your input.
In particular, if you know your input is sorted, it suffices to compare the first and last strings (see Richard's answer).
i - Find the file which has the least folder depth (i.e. baz.txt) - it's root path is home
ii - Then go through the other strings to see if they start with that root.
iii - If so then remove root from all the strings.
Start with std::size_t index=0;. Scan the list to see if characters at that index match (note: past the end does not match). If it does, advance index and repeat.
When done, index will have the value of the length of the prefix.
At this point, I'd advise you to write or find a string_view type. If you do, simply create a string_view for each of your strings str with start/end of index, str.size().
Overall cost: O(|prefix|*N+N), which is also the cost to confirm that your answer is correct.
If you don't want to write a string_view, simply call str.erase(str.begin(), str.begin()+index) on each str in your vector.
Overall cost is O(|total string length|+N). The prefix has to be visited in order to confirm it, then the tail of the string has to be rewritten.
Now the cost of the breadth-first is locality, as you are touching memory all over the place. It will probably be more efficient in practice to do it in chunks, where you scan the first K strings up to length Q and find the common prefix, then chain that common prefix plus the next block. This won't change the O-notation, but will improve locality of memory reference.
for(vector<string>::iterator itr=V.begin(); itr!=V.end(); ++itr)
itr->erase(0,6);

Is there a way to replace string ">" with > in an 'if' condition?

I came across the below use case, but I could not find a proper solution.
Is there a way to replace string "<" or ">" with condition < or > in an if condition?
Example:
string condition = "<";
if (10 condition 8) // Here I want to replace condition with <
{
// Some code
}
I don't want to do it like:
if ("<" == condition)
{
if (10 < 8)
{
}
}
else if (">" == condition)
{
if (10 > 10)
{
}
}
And my condition will change during run time. I am just searching for a simple way if exist apart from above.
Use case: The user will give some query like below:
input: 10 > 9 => output: true
input: 10 < 7 => output: false
Basically I need to parse this query, as I have these 3 words (10, >, 9) as strings, and somehow I want to convert string ">" or "<" to actual symbol > or <.
You can map the string to a standard library comparator functor such as std::less via a std::map or a std::unordered_map.
You can't create a new operator in C++ (Can I create a new operator in C++ and how?). I can see where you are coming from with this idea, but the language just doesn't support that. You can, however, create a function that takes two operands and a string "argument" and returns the appropriate value.
bool CustomCompare(int operand1, int operand2, string op)
{
if (op == "<")
{
return operand1<operand2;
}
if (op == ">")
{
return operand1>operand2;
}
if (op == "_")
{
return DoTheHokeyPokeyAndTurnTheOperandsAround(operand1, operand2);
}
}
std::function<bool(int,int)> comparator = std::less;
if(comparator(10, 8))
{
//some code
}
See Also:
http://en.cppreference.com/w/cpp/utility/functional/function
http://en.cppreference.com/w/cpp/utility/functional/less
#include <functional>
#include <map>
#include <string>
int main()
{
using operation = std::function<bool(int,int)>;
std::map<std::string, operation> mp =
{{"<", std::less<int>()},
{">", std::greater<int>()}};
int x = 5;
int y = 10;
std::string op = "<";
bool answer = mp[op](x, y);
}
If you are a C++ Ninja, and you are very stubborn to get it working just the way you wish, there is a way, but it is advanced and complicated.
I mostly write POSIX code for VxWorks, but I guess it can be done for any other.
Let's say you have: string myExpression = "mySize > minSize";
"Rebuild the String as a C code" (save to file, use ccppc, gcc, gpp, whatever toolchain you have.)
You need to link it with your code, at least to get ELF relocations for mySize & minSize (I think it can be done using app-load, if you customize your ld command.
Load the code using ld
Jump to the new address you loaded your code to.
All that said, I would not recommend you to do that:
Very complicated.
Not the most stable, and very bug/error prone.
Can lead to major vulnerabilities "Hacker" style,
and proper sanitation is required.
The only pro I can see, is that this method supports everything C has to offer out of the box! BitWise, +-/*^!, even functions as pow(), and such.
A little bit better is:
To compile a function as:
`"bool comparer_AB(int a, int b) { return a " + operator + "}"`
and then call comparer_AB();.

Creating an Interactive Prompt in C++

I have a program which should read commands from the console and depending on the command perform one of several actions. Here is what I have so far:
void ConwayView::listening_commands() {
string command;
do {
cin >> command;
if ("tick" == command)
{
// to do
}
else if ("start" == command)
{
// to do for start
}
...
} while (EXIT != command);
}
Using a switch in place of the if statements helps a little if there are a large amount of commands. What patterns do you suggest using to provide the interactive command line?
There are multiple ways to solve this and it's debatable what the "right" solution is. If I were to solve it for my own work, I would create a table of a custom struct. Something like:
struct CommandStruct {
char *command;
int (*commandHandler)(/*params*/);
} commandTable[] = {
{ "tick", tickCommand },
{ "start", startCommand },
...
};
Then my processing loop would walk through each element of this table, looking for the right match, such as:
for (int i = 0; i < TABLE_SIZE; ++i) {
if (command == commandTable[i].command) { /* using whatever proper comparison is, of course */
commandTable[i].commandHandler(/*params*/);
break;
}
}
Not really a pattern, but often a good approach:
#include <map>
#include <functional>
#include <string>
#include <iostream>
typedef std::map< std::string, std::function<void(void)> > command_dict;
// ^^^^^^^^
// the signature of your commands. probably should have an error code.
void command1() { std::cout << "commanda" << std::endl; }
void command2() { std::cout << "commandb" << std::endl; }
void command3() { std::cout << "commandc" << std::endl; }
int main() {
command_dict c;
c["a"] = &command1;
c["b"] = &command2;
c["c"] = &command3;
std::string input;
while(std::getline(std::cin, input)) { // quit the program with ctrl-d
auto it = c.find(input);
if(it != end(c)) {
(it->second)(); // execute the command
} else {
std::cout << "command \"" << input << "\" not known" << std::endl;
}
}
}
If the number of command is small and possible parameters are really few, you could keep on with switch case !
If the number of commands increases, consider the command design pattern (which is IMHO some sort of strategy pattern disguised: cf Using a strategy pattern and a command pattern for the differences between command and strategy patterns).
If most of your commands are all sharing a part of the same behaviour, don't forget the template method pattern.
If the complexity for creating your command objects increases ( i.e. there is complexity in decoding/understanding the input of your command line), you should start looking at the interpreter design pattern
If while designing with the help of the interpreter pattern, you happen to see some complexity ( if the interpreter needs too much work, you see syntax issues and so on ), then you should probably look at DSL, domain specific language, and design your own language that fits (and only fits) to you own inputs.
The if-else ladder is fine.
It can in principle be replaced with a map<string, Function>, but that gains you nothing for this concrete case (it is added complexity for no particular gain, even with a high number of commands).
When I wrote this initially I forgot to mention though:
Make your command handlers separate functions.
If you don’t, then the if-else ladder can become quite messy… The map solution requires separate functions, and can therefore appear to be a little more clean than an everything-directly-here if-else ladder. But it’s really the separate functions that then provide a measure of clarity, while the map detracts a little (adding extra work in maintaining the map, and an extra level of indirection to cope with).
On the other hand, since “read commands from the console” indicates interactive input, with a user in the picture, you don’t want to read two or more commands from the same line of input. Because that would screw up the prompting, and can seem quite baffling to the user. So instead of reading a “word” of input at a time using >>, use std::getline to a read a full line of input at a time.
Use the new and improved way to preform a bunch of commands at will:
int happy_time = 5;
int a = happy_time;
int muddy_dirt = 1;
int b = muddy_dirt;
int c = happy_time * muddy_dirt //really messy stuff
that's probably the least complicated way to do it...
You must use database like access if your command is large.

Evaluating expressions inside C++ strings: "Hi ${user} from ${host}"

I'm looking for a clean C++ way to parse a string containing expressions wrapped in ${} and build a result string from the programmatically evaluated expressions.
Example: "Hi ${user} from ${host}" will be evaluated to "Hi foo from bar" if I implement the program to let "user" evaluate to "foo", etc.
The current approach I'm thinking of consists of a state machine that eats one character at a time from the string and evaluates the expression after reaching '}'. Any hints or other suggestions?
Note: boost:: is most welcome! :-)
Update Thanks for the first three suggestions! Unfortunately I made the example too simple! I need to be able examine the contents within ${} so it's not a simple search and replace. Maybe it will say ${uppercase:foo} and then I have to use "foo" as a key in a hashmap and then convert it to uppercase, but I tried to avoid the inner details of ${} when writing the original question above... :-)
#include <iostream>
#include <conio.h>
#include <string>
#include <map>
using namespace std;
struct Token
{
enum E
{
Replace,
Literal,
Eos
};
};
class ParseExp
{
private:
enum State
{
State_Begin,
State_Literal,
State_StartRep,
State_RepWord,
State_EndRep
};
string m_str;
int m_char;
unsigned int m_length;
string m_lexme;
Token::E m_token;
State m_state;
public:
void Parse(const string& str)
{
m_char = 0;
m_str = str;
m_length = str.size();
}
Token::E NextToken()
{
if (m_char >= m_length)
m_token = Token::Eos;
m_lexme = "";
m_state = State_Begin;
bool stop = false;
while (m_char <= m_length && !stop)
{
char ch = m_str[m_char++];
switch (m_state)
{
case State_Begin:
if (ch == '$')
{
m_state = State_StartRep;
m_token = Token::Replace;
continue;
}
else
{
m_state = State_Literal;
m_token = Token::Literal;
}
break;
case State_StartRep:
if (ch == '{')
{
m_state = State_RepWord;
continue;
}
else
continue;
break;
case State_RepWord:
if (ch == '}')
{
stop = true;
continue;
}
break;
case State_Literal:
if (ch == '$')
{
stop = true;
m_char--;
continue;
}
}
m_lexme += ch;
}
return m_token;
}
const string& Lexme() const
{
return m_lexme;
}
Token::E Token() const
{
return m_token;
}
};
string DoReplace(const string& str, const map<string, string>& dict)
{
ParseExp exp;
exp.Parse(str);
string ret = "";
while (exp.NextToken() != Token::Eos)
{
if (exp.Token() == Token::Literal)
ret += exp.Lexme();
else
{
map<string, string>::const_iterator iter = dict.find(exp.Lexme());
if (iter != dict.end())
ret += (*iter).second;
else
ret += "undefined(" + exp.Lexme() + ")";
}
}
return ret;
}
int main()
{
map<string, string> words;
words["hello"] = "hey";
words["test"] = "bla";
cout << DoReplace("${hello} world ${test} ${undef}", words);
_getch();
}
I will be happy to explain anything about this code :)
How many evaluation expressions do intend to have? If it's small enough, you might just want to use brute force.
For instance, if you have a std::map<string, string> that goes from your key to its value, for instance user to Matt Cruikshank, you might just want to iterate over your entire map and do a simple replace on your string of every "${" + key + "}" to its value.
Boost::Regex would be the route I'd suggest. The regex_replace algorithm should do most of your heavy lifting.
If you don't like my first answer, then dig in to Boost Regex - probably boost::regex_replace.
How complex can the expressions get? Are they just identifiers, or can they be actual expressions like "${numBad/(double)total*100.0}%"?
Do you have to use the ${ and } delimiters or can you use other delimiters?
You don't really care about parsing. You just want to generate and format strings with placeholder data in it. Right?
For a platform neutral approach, consider the humble sprintf function. It is the most ubiquitous and does what I am assuming that you need. It works on "char stars" so you are going to have to get into some memory management.
Are you using STL? Then consider the basic_string& replace function. It doesn't do exactly what you want but you could make it work.
If you are using ATL/MFC, then consider the CStringT::Format method.
If you are managing the variables separately, why not go the route of an embeddable interpreter. I have used tcl in the past, but you might try lua which is designed for embedding. Ruby and Python are two other embeddable interpreters that are easy to embed, but aren't quite as lightweight. The strategy is to instantiate an interpreter (a context), add variables to it, then evaluate strings within that context. An interpreter will properly handle malformed input that could lead to security or stability problems for your application.