A systematic approach to creating a simple test parser
As far as I can tell, you can model this easily using any number of formalisms. Of course, if you insist on the specific syntax you have invented, you may be out of luck and may have to build your own engine.

I wouldn't to that if I were you: you have both forward and backward references, and your "data access" tokens closely resemble your "logic" tokens, so processing may become troublesome.

Consider this instead:

{if weight}; Weight is: {weight}kg{endif}


This can easily be parsed using standard techniques, and is immediately familiar to many people. It also supports nesting (if you use a context-free parser).



That all said, here is a sketch of an algorithm that will parse your syntax, assuming that there is no nesting at all (which you don't seem to specify).

We simply work in two phases:


Lex the input into tokens: regular text, and your special tokens. Represent the former by text(text) latter by two types, data(name) and conditional(left, right, text).


Go over the token list, evaluating each token according to these rules:

 eval text(t) ==&gt; t
 eval data(n) ==&gt; value(n)
 eval conditional(left, right, text) ==&gt;  
    if   (!left || (eval predecessor) != "")  
      &amp;&amp; (!right || (eval successor) != "") {
        text
    } else {
        ""
    }




You see that you have to keep two copies in memory, at least for a time.

I think it's straight forward to transform this solution so that you move a three-token window over the token stream; this way, you can forget old tokens, and only need to lex one token in advance. So, as long as your conditional tokens only depend on their immediate neighbours, this can be efficiently parsed.