Exiting a loop half way through

B

Buster Copley

While playing around with my quine I was reminded
of a situation I have come across before: when
the exit-condition for a loop needs to be checked
in the middle of a loop, rather than at the
beginning (while) or the end (do ... while). It
always seems to come up when I'm hand-rolling very
simple parsers. (Doctor, it hurts when I do this ...)

Anyone want to argue for or against any of these
three alternatives, or suggest something better?

template <typename RulesFuction>
void format (const string & s, RulesFunction f)
{
// f will be applied to an iterator to a '%' character.
// Applying f should return an iterator to the character
// after the whole '%' escape sequence.
// Side-effects of f should be limited to output on cout.

iter b (s.begin ()), e (s.end ()), i;
ostream_iterator <char> out (cout);

#if defined A

copy (b, i = find (b, e, '%'), out);
while (i != e) {
b = f (i);
copy (b, i = find (b, e, '%'), out);
}

#elif defined B

while (true) {
copy (b, i = find (b, e, '%'), out);
if (i == e) break;
b = f (i);
}

#else

goto start;
while (i != e) {
b = f (i);
start: copy (b, i = find (b, e, '%'), out);
}

#endif

}
 
B

Buster Copley

Buster said:
While playing around with my quine

Practice what you preach, Buster. The complete,
compilable code follows. You can see which way
I've settled on at the moment.

#include <iostream>
#include <ostream>
#include <string>
#include <algorithm>
#include <iterator>
using namespace std;
typedef string::const_iterator iter;

template <typename F>
void format (const string & s, F f) {
iter b (s.begin ()), e (s.end ()), i;
ostream_iterator <char> out (cout);
goto start;
while (i != e) {
b = f (i);
start: copy (b, i = find (b, e, '%'), out);
}
}

iter p (iter i) {
cout << '%' << * ++ i;
if (* i == 'n') cout << "\"\n \"";
return ++ i;
}

struct q {
iter operator () (iter i) {
switch (* ++ i) {
case 's': format (s, p); break;
case 'n': cout << '\n'; break;
case 'q': cout << '\"'; break;
case 'b': cout << '\\'; break;
default: cout << * i;
}
return ++ i;
}
q (const string & s) : s (s) { }
const string & s;
};

int main () {
string s (
"#include <iostream>%n"
"#include <ostream>%n"
"#include <string>%n"
"#include <algorithm>%n"
"#include <iterator>%n"
"using namespace std;%n"
"typedef string::const_iterator iter;%n"
"%n"
"template <typename F>%n"
"void format (const string & s, F f) {%n"
" iter b (s.begin ()), e (s.end ()), i;%n"
" ostream_iterator <char> out (cout);%n"
" goto start;%n"
" while (i != e) {%n"
" b = f (i);%n"
" start: copy (b, i = find (b, e, '%%'), out);%n"
" }%n"
"}%n"
"%n"
"iter p (iter i) {%n"
" cout << '%%' << * ++ i;%n"
" if (* i == 'n') cout << %q%b%q%bn %b%q%q;%n"
" return ++ i;%n"
"}%n"
"%n"
"struct q {%n"
" iter operator () (iter i) {%n"
" switch (* ++ i) {%n"
" case 's': format (s, p); break;%n"
" case 'n': cout << '%bn'; break;%n"
" case 'q': cout << '%b%q'; break;%n"
" case 'b': cout << '%b%b'; break;%n"
" default: cout << * i;%n"
" }%n"
" return ++ i;%n"
" }%n"
" q (const string & s) : s (s) { }%n"
" const string & s;%n"
"};%n"
"%n"
"int main () {%n"
" string s (%n"
" %q%s%q);%n"
" format (s, q (s));%n"
"}%n"
"");
format (s, q (s));
}
 
W

White Wolf

Buster said:
While playing around with my quine I was reminded
of a situation I have come across before: when
the exit-condition for a loop needs to be checked
in the middle of a loop, rather than at the
beginning (while) or the end (do ... while). It
always seems to come up when I'm hand-rolling very
simple parsers. (Doctor, it hurts when I do this ...)

Anyone want to argue for or against any of these
three alternatives, or suggest something better?

copy (b, i = find (b, e, '%'), out);
while (i != e) {
b = f (i);
copy (b, i = find (b, e, '%'), out);

Code duplication.
#elif defined B

while (true) {
copy (b, i = find (b, e, '%'), out);
if (i == e) break;
b = f (i);

How I used to do that (if I had to) was to add // NOTE! after the break.
So no one will miss it.
goto start;
while (i != e) {
b = f (i);
start: copy (b, i = find (b, e, '%'), out);

Ahh. I looked at a goto. Now I have to go and confess. :)

I sort of like that. It reminds me of the Duff's device and this:

http://www.cuj.com/documents/s=8890/cujexp0310dewhurst/

Since I am coming down with a fever (and it is not Saturday night here) I
might have missed important things here.
 
K

Kevin Saff

White Wolf said:
How I used to do that (if I had to) was to add // NOTE! after the break.
So no one will miss it.

Hello, Wolf and Buster.

Did you ever consider:

while(true)
{
doSomethingFirst();
if (condition)
break;

doSomethingElse();
}

or possibly even (although I wouldn't do this):

while(true)
{
doSomethingFirst();

if (condition) break;

doSomethingElse();
}

To me whitespace seems the most natural way to emphasize control statements,
since most whitespace is already used for that very purpose.
 
B

Buster Copley

White said:
Code duplication.

Yeah, that's my least favourite.
How I used to do that (if I had to) was to add // NOTE! after the break.
So no one will miss it.

Good call.
Ahh. I looked at a goto. Now I have to go and confess. :)

I sort of like that.

Me too.
It reminds me of the Duff's device and this:

http://www.cuj.com/documents/s=8890/cujexp0310dewhurst/

Since I am coming down with a fever (and it is not Saturday night here) I
might have missed important things here.

Thanks a lot for your comments.
 
B

Buster

Kevin Saff said:
while(true)
{
doSomethingFirst();
if (condition)
break;

doSomethingElse();
}

To me whitespace seems the most natural way to emphasize control statements,
since most whitespace is already used for that very purpose.

Thanks very much for your response.
Buster
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top