News Delta Vee!

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,628
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Arguing about coding styles is pointless IMHO. Choose one and stick to it, except if you work in a team where one style is already used. For the later the team should agree on one and move on.

Yes, but you should select one style in your code and keep it. Not have chaos. Simply for reading your own code.

"Goto" is a valid command, and in fact the processor itself works this way, so a "goto" has often higher performance than anything else. But using "goto" in your code extensively is also often leading to spaghetti code, as countless examples have shown in the past. Completely omitting "goto" - and only using structured loops/functions - proved itself to be a strategy to yield clean code more often than not. But of course you can also create clean code while using some "gotos" here and there. Many Linux kernel drivers are a good example for that.

Also, you can use the better named versions of goto, which I prefer:

break, continue, return.

Sadly, C++ does not know the named break statement of Java.

Code:
outer_loop: for(String x : lines) {
    do_something();
    for(String token: x.split("\s")) {
        do_something_else_with(token);
        if(something_interesting(token))
            break outer_loop;
    }
}
 

george7378

DON'T PANIC
Addon Developer
Donator
Joined
Jun 26, 2009
Messages
1,045
Reaction score
0
Points
36
Dang! I tried that, but it spat out an odd sounding error at compile-time

Code:
1>------ Build started: Project: Delta Vee!, Configuration: Debug Win32 ------
1>cl : Command line error D8016: '/clr' and '/MT' command-line options are incompatible
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Never seen that before! What version of visual studio are you using? Here's something to try - go to file -> new project and create an 'empty project'. When your blank project has been created, right click on 'source files' on the left, and add a new .cpp file (doesn't matter what you call it). Then paste your code into that new file, change it to multi-threaded as I said before, and compile again. I always create an empty project when I start something new, and it seems to compile fine for me.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,628
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Never seen that before! What version of visual studio are you using? Here's something to try - go to file -> new project and create an 'empty project'. When your blank project has been created, right click on 'source files' on the left, and add a new .cpp file (doesn't matter what you call it). Then paste your code into that new file, change it to multi-threaded as I said before, and compile again. I always create an empty project when I start something new, and it seems to compile fine for me.

That is the problem because he uses .NET CLR as output. Not the usual problem for Orbiter add-ons.
 

johan

Donator
Donator
Joined
Jun 30, 2010
Messages
112
Reaction score
0
Points
16
Code:
	string Continue = "Continue";
	string Exit = "Exit";
	string yes = "yes";
	string Yes = "Yes";
	string YES = "YES";
	string YEs = "YEs";
	string YeS = "YeS";
	string yES = "yES";
	string yeS = "yeS";
	string yEs = "yEs";

Howdy. Perhaps you've figured this out already, apologies if this is the case.

For this sort of thing, rather do everything in one case:

Code:
string exit = "EXIT";
string continue = "CONTINUE";
string yes = "YES";

Then when you need to compare input to those, you convert whatever the user typed to uppercase. Java has a function on the String class, I can't remember now what C++ uses but there will be some super-simple way to do it. If you want to be thorough, you also trim the user's input string, so if someone accidentally adds a space on either end of their input, your comparison still works. I always use upper case, but lower case will work out the same.

This is more robust and leads to a LOT fewer lines of code & comparisons. Which will make you code fewer bugs.

---------- Post added at 14:09 ---------- Previous post was at 14:05 ----------

Also I take it you've made a bunch of changes based on the fact that there's been 2 pages worth of conversation :)

Would you mind posting updated code?
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
Yes, but you should select one style in your code and keep it.

This is what I meant with "choose one and stick to it".

Also, you can use the better named versions of goto, which I prefer:

break, continue, return.

"goto" does other things than those three. They are no "better named" versions of it, they are elements of a different flow control concept. Now I know that you certainly know this, I just wanted to point it out to the OP.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,628
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
"goto" does other things than those three. They are no "better named" versions of it, they are elements of a different flow control concept. Now I know that you certainly know this, I just wanted to point it out to the OP.

Essentially (and from a classic programming language view), they are specialized and more suitable named versions of goto (which Djikstra back then also mentioned, not that I share his blunt criticism there, but he had a point). There are very few situations, in which a classic goto is really needed and brings advantages. It is better to pretend that goto does not exist for a while.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
Essentially (and from a classic programming language view), they are specialized and more suitable named versions of goto (which Djikstra back then also mentioned, not that I share his blunt criticism there, but he had a point).

I disagree. A "goto" is defined by two elements:
1. It sets the program flow to a different location unconditionally.
2. It lets the programmer specify an arbitrary location within the code.

The mentioned flow control elements might have the same effect like a "goto" sometimes (in classic programming language sense and/or machine code), but are not different versions of it. The concept simply is a different one, both in programming language view and machine code. The direct hint for this is that "continue"&co do not let the programmer set an arbitrary location. It is fixed to the current block's end (or conditionally the beginning in the case of a "continue").

This difference gets more obvious if you create a compiler or interpreter from scratch. A "goto" is easier to implement for most targets than "continue"&co. The later often yields different machine code in different situations (context, optimization parameters, etc.), while the former mostly stays as is: a simple jump.

If anything, then "continue"&co could be understood as macros that create different jumps for different situations, but even that would be a far stretch. Let's just say it is a different flow control concept in contrast to the very simplistic "goto" command, so newbies are not confused.

I also disagree with the notion to pretend that the command is not there. Newcomers should know about it and acknowledge it as a very, very, low-level way to control the program flow. They should know that it is useful in certain situations, but that just like an inline-assembler you should know what you are doing before you use it.
 

johan

Donator
Donator
Joined
Jun 30, 2010
Messages
112
Reaction score
0
Points
16
...They should know that it is useful in certain situations, but that just like an inline-assembler you should know what you are doing before you use it.

This seems to me to be the salient point that needs to be made on this thread.

For the rest of the "goto" argument, are we drifting towards going off topic?
 

Ghostrider

Donator
Donator
Joined
Feb 16, 2008
Messages
3,606
Reaction score
2
Points
78
Location
Right behind you - don't look!
Ah, GOTO... The bane of programmers back in the times of the Home Computer Revolution. Budding programmers were told to avoid it at all costs, relying instead on subroutine calls (GOSUB/RETURN) because it made for more structured and elegant code. Unfortunately I learned from early manuals that did not follow the rule. You could lose the flow pretty quickly if the code was just a little bit complex.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,628
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
And I disagree as well there. You exceptionalize goto.

But lets start at the definition:

A "goto" is defined by two elements:
1. It sets the program flow to a different location unconditionally.
2. It lets the programmer specify an arbitrary location within the code.

This is true for the current modern goto statement in most programming languages. But historically, continue, break and, in a wider sense, return had been implemented as gotos before their conception. These keywords represent unconditional jumps or branches in the program flow to a special location depending on the context of their call. Not arbitrary locations, but a location that you would very often "goto" to, if you would not have such special keywords. You use them for solving problems, that had traditionally been solved by a goto and which quickly degenerated into something unreadable. For example when the label for "leave the loop" was suddenly a lot of code away from the loop without you remembering this detail (which happens often, even to the best programmers)


This difference gets more obvious if you create a compiler or interpreter from scratch. A "goto" is easier to implement for most targets than "continue"&co. The later often yields different machine code in different situations (context, optimization parameters, etc.), while the former mostly stays as is: a simple jump.

If you do a goto between two different scopes, the resulting code will be everything but a simple jump. It will on a good compiler be not different to a simple goto instruction doing the same. Optimization will usually rather punish you for the goto, than for the more specialized instructions, because your goto does not contain any semantic context for the optimizer to consider. It can even make something as sophisticated as LLVM run out of good answers.

Even throwing an exception, which is another form of a branch in the program flow, is not different to a goto to the right exception handler, if you execute the same actions as the "throw" instruction or the compiler for finding the right exception handler. It is a lot of more code that happens for giving you predictive results.

I also disagree with the notion to pretend that the command is not there. Newcomers should know about it and acknowledge it as a very, very, low-level way to control the program flow. They should know that it is useful in certain situations, but that just like an inline-assembler you should know what you are doing before you use it.

If a generic goto is only useful in maybe 0.1% of all cases (which it is in my experience, unless you consider shaders, OpenCL kernels or low level device drivers as 50% of your world view), it makes no sense at all to waste breath on teaching beginners its existence. While I don't go as far as Djikstra to consider the goto instruction itself harmful, I consider teaching already beginners its existence harmful to their skills. First of all, goto is a Mephisto among the C++ statements. It promises you speed and optimized code, and at the same time it lures you away from it. It takes a lot of discipline and experience to harnish goto into something useful. goto is a statement, that you first need to learn how to not use it, before you start seeing every problem as something that a goto can solve in first place.

Second, goto is not necessary for normal applications. Most problems you will encounter, that a goto can solve, will be: aborting a loop, terminating the body of a loop, leave a switch block, quickly roll up large nested if-statements or leaving a function.

Except the quick rolling up of many nested if statements, you have special keywords for special short-cut branches for that task. And the nested if statements are not necessary to exist in first place, breaking them down into (inline) functions is a much better solution that making things more complex with a goto. And this often also helps you seeing hints for refactoring the logic and find a smarter logic.

Same with the inline assembler. Yes, it exists. Yes, it has its use. No, a beginner can't use it properly and experimenting with it will only make the beginner get frustrated for even simple problems. (Unless you have an experienced assembler guy there. Then you usually only have to force him write alternative functions without inline assembler and talk with him about labor costs from time to time)

What is the gain in that style of teaching? For teaching people to program, you need to teach them to solve problems that they will encounter with focus on the everyday problems at the beginning. Because you won't learn a programming language (or a framework, library, API in that context) fast without also learning how to solve problems with it.

Nobody learns french in his lifetime by opening a dictionary and starting with "a". You first teach them to introduce themselves and ask for the way to the next train station. And much later, you start teaching them the fine details of the language that they may encounter in sophisticated literature.

And finally: Something about the goto statement, that I can subscribe to: http://www.stevemcconnell.com/ccgoto.htm
 
Last edited:

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
And I disagree as well there.
<snip>

Then we at least agree to disagree.

What is the gain in that style of teaching? For teaching people to program, you need to teach them to solve problems that they will encounter with focus on the everyday problems at the beginning. Because you won't learn a programming language (or a framework, library, API in that context) fast without also learning how to solve problems with it.

Well, it is interesting that the first use of "goto" in this example here came up all by itself. Nobody "taught" BruceJohnJennerLawso about "goto" here in first place. Maybe if somebody did, and did it right by means of explaining why it is a bad idea, he would not have tried it.

So I would say the gain of my style of answering questions (not what you exaggerated here with your french teaching example) is to prevent learners from falling into pitfalls.

Don't get me wrong, I'm not claiming that a "reference-book" approach to teaching C++ is the right thing to do. But letting them "discover" that command (and the corresponding flow control concept) by accident is not a particularly fortunate one, either. And exactly this seems to be what happened here.

I prefer to tell people as much as I know about a certain topic, if they honestly ask for an explanation. I think Bruce just did that with
-Anything wrong with gotos performance-wise? I find it much easier to use naturally, its nice to be able to think of things in terms of linearity. I guess more experienced programmers aren't concerned with that so much though.

I can't answer that with "just use the better named versions 'continue', 'break' and 'return'".
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,628
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
I can't answer that with "just use the better named versions 'continue', 'break' and 'return'".

Well, you could answer:

"Hell no, that is everything but linear! Don't fool yourself there."

But I found my answer better.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
Well, you could answer:

"Hell no, that is everything but linear! Don't fool yourself there."

But I found my answer better.

Hell no, that is everything but nice! :lol:
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,628
Reaction score
2,345
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Hell no, that is everything but nice! :lol:

See. Teaching programming is something for the real gurus. I'll stick to getting taught. :lol:
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
Can we goto a specialized thread for this?
 

Ghostrider

Donator
Donator
Joined
Feb 16, 2008
Messages
3,606
Reaction score
2
Points
78
Location
Right behind you - don't look!
See. Teaching programming is something for the real gurus.

As long as you can get them out of their meditation, of course.:lol:

guru-meditation.gif


Ah, multitasking... :)
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
Can we goto a specialized thread for this?

Would be a rather near jump given that it is close to the topic of discussing a learner's code. But I see what you mean.

I second Johan's call for an updated version of the code, though. Seeing what progress Bruce made should be interesting.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Me neither re-Glideslope. I would hack down a glideslope on a 40 degree AoA, get somewhere close to the runway and then use the engines to do altitude holds / speed holds etc. It was chatting with Phantom Cruiser that got me thinking about deadstick landings and teardrop turns, etc and coming in on no engines. Which got me to Glideslope 1 and my frustration that it was not complete source (the parse functions were all missing and it was hardly documented), which got me to think 'damnit ... I want to write a Glideslope 2 to continue the legacy of that awesome code and restore it to full open source'. It was a massive voyage of understanding, and if you ever download it and look at the source, you can see how complex it is. I was doing a refresher in C++, a primer in Orbiter API's, a real schooling in Orbiter's interesting MFD behaviors, and a massive schooling in coordinate systems, matrices and vector theory. And it was exhilarating and rewarding as hell to get it to work and I see a few people download it and like it too! So now the same with RV Orientation ... my docking HUD code with my buddy Enjo's HUD hooker code whose code takes awesome to another level!!


On parsing ... have a look at this from Glideslope 2 (ParseFunctions.cpp code):

Code:
//
// Parse Helper Functions
//
// Purpose ... tokenize strings, pull out floats, deal with quoted strings, etc
//
// (c) Andrew Stokes (ADSWNJ) 2012
//
// All rights reserved
//

#include <math.h>
#include <stdio.h>
#include <string.h>

//
// ParseQuotedString:
// Pull out a quoted string from the buffer pointer to by bp into ret
// After the function, ret points to the quoted string (quotes stripped), and bp points to the rest of the string
// Note 1 ... the buffer is modified (nuls added to terminate strings). 
// Note 2 ... escaped characters are not handled (e.g. \" terminates the string and leaves a \). 
// Return status reflects whether the task was successful. 
//

  bool ParseQuotedString(char **bp, char **ret) {
	  char *b = *bp;
	  while ((*b==' ')||(*b=='\t')) b++;
	  if (*b!='\"') return false;
	  b++;
	  *ret = b;
	  while ((*b!='\"')&&(*b!='\0')&&(*b!='\n')) b++;
	  if (*b!='\"') return false;
	  *b = '\0';
	  *bp = b+1;
	  return true;
  }
//
// ParseString:
// Same as ParaseQuotedString except does not want quotes and stops at the first whitespace
//

  bool ParseString(char **bp, char **ret) {

	  char *b = *bp;
	  while ((*b==' ')||(*b=='\t')) b++;
	  *ret = b;
	  while ((*b!='\"')&&(*b!='\0')&&(*b!='\n')&&(*b!=' ')&&(*b!='\'')&&(*b!='\t')) b++;
	  if ((*b=='\"')||(*b=='\'')) return false; // No quotes allowed in string
	  if (*b!='\0') {
		*b = '\0';
		*bp=b+1;
	  } else {
		*bp = b;	// if we hit EOL, point to EOL not one beyond
	  }
	  return true;
  }
// 
// ParseDouble:
// Same as ParaseString except it pulls out a double floating point
//

  bool ParseDouble(char **bp, double *ret) {
	  char *b = *bp;
	  char *t;
	  int i;

	  while ((*b==' ')||(*b=='\t')) b++;
	  t = b;
	  i = strspn(t, "+-0123456789e.");
	  b = t+i;
	  if ((*b!=' ')&&(*b!='\t')&&(*b!='\n')&&(*b!='\0')) return false; // End of parse must be whitespace
	  if (*b!='\0') {
		*b = '\0';
		*bp=b+1;
	  } else {
		*bp = b;	// if we hit EOL, point to EOL not one beyond
	  }
	  if (i==0) return false;
	  *ret = atof(t);
	  return true;
  }
// 
// ParseInt:
// Same as ParaseString except it pulls out an integer
//
  bool ParseInt(char **bp, int *ret) {
	  double f=0.0;
	  if (!ParseDouble(bp,&f)) return false;
	  *ret=int(f);
	  return true;
  }
// 
// ParseBool:
// Same as ParaseString except it pulls out a true or false
//
  bool ParseBool(char **bp, bool *ret) {
	  char *bufp;
	  if (!ParseString(bp,&bufp)) return false;
	  if (_stricmp(bufp,"FALSE")==0) {
		  *ret = false;
		  return true;
	  }
	  if (_stricmp(bufp,"TRUE")==0) {
		  *ret = true;
		  return true;
	  }
	  return false;
  }

It's called like this...

Code:
//
//
//  Configuration Load & Parse Code
//
//
void Glideslope::LoadConfig () {
  FILE* GS2cfg;
//  int scancount;
  char buf[256];
  char bufcpy[256];
  buf[255] = '\0';
  char *tok=buf;
  char *strtok=buf;
  double tokf[7];
  int j;
  int ofs;
  int modeTok[3];
  bool unitstok = false;

  char *bp;
  bool prefsFound = false, runwayFound = false, baseFound = false, gsFound = false;

  GS2cfg = fopen(".\\Config\\MFD\\GS2\\GS2.cfg","r");
  if (GS2cfg == NULL) {
// Defaults to init code
	  LoadDefaultConfig();
	  return;
  }

  G->maxMod=4;
  G->hacRadius = 15000;
  G->finalDist = 20000;
  G->BaseCount = 0;
  G->RunwayCount = 0;
  G->GSfileCount = 0;

  FILE* GS2CfgPL=fopen(".\\Config\\MFD\\GS2\\Logs\\GS2cfgParselog.txt","w");
  fprintf(GS2CfgPL,"Successfully found and opened GS2.cfg\n");

  while (fgets(buf,255,GS2cfg)!=NULL) {
	  bp=buf;
	  sprintf(bufcpy,"%s",buf);
	  while (bp[0]==' ' || bp[0]=='\t') bp++;
	  if ((bp[0]=='\0')||(bp[0]=='\n')) {
      fprintf(GS2CfgPL,"NUL> %s", buf);
	    continue;
	  }
	  if (bp[0]==';') {
      fprintf(GS2CfgPL,"REM> %s", buf);
	    continue;
	  }

	  if (!ParseString(&bp,&tok)) goto badparse;

	  if (_stricmp(tok,"BASE")==0)
	  {
// Parsing BASE "base name" lon lat
// e.g.    BASE "Cape Canaveral" -80.675 +28.5208

	    if (!ParseQuotedString(&bp,&strtok)) goto badparse;
	    if (strlen(strtok)>32) goto badparse;
	    for (j=0; j<2; j++) {
	      if (!ParseDouble(&bp,&(tokf[j]))) goto badparse;
	    }
	    if (G->BaseCount >= G->BASE_LIMIT) goto badparse;
	    sprintf(G->BaseName[G->BaseCount],strtok);
	    G->BaseLL[G->BaseCount][0] = tokf[1];
	    G->BaseLL[G->BaseCount][1] = tokf[0];
	    fprintf(GS2CfgPL,"BASE LOADED: %s Lon:%.3f Lat:%.3f\n", G->BaseName[G->BaseCount],G->BaseLL[G->BaseCount][1],G->BaseLL[G->BaseCount][0] );
	    baseFound = true;
	    G->BaseCount++;
	    continue;
	  }

	  if (_stricmp(tok,"RUNWAY")==0)
	  {
// Parsing RUNWAY "{basename}" "{rwyname}" {end1-1} {end1-3} {end2-1} {end2-3} {papi} {vasi} {alt}
// e.g.    RUNWAY "Cape Canaveral" "KSC33" -8220 -600 -12670 -3155 -2000 671 2.6

	    if (!ParseQuotedString(&bp,&strtok)) goto badparse;
	  
	    for (ofs=0; (ofs<G->BaseCount) && (_stricmp(strtok,(G->BaseName[ofs]))!=0) ; ofs++) {}
	    if (ofs==G->BaseCount) goto badparse;

	    if (!ParseQuotedString(&bp,&strtok))  goto badparse;
	    if (strlen(strtok)>12) goto badparse;

	    for (j=0; j<6; j++) {
	      if (!ParseDouble(&bp,&(tokf[j]))) goto badparse;
	    }
      if (!ParseDouble(&bp,&(tokf[6]))) tokf[6] = 0.0; // Parse Altitude, but default to zero if we can't read it

      if (G->RunwayCount >= G->RUNWAY_LIMIT) goto badparse;

	    sprintf(G->RunwayName[G->RunwayCount],strtok);
	    for (j=0;j<2;j++) G->RunwayData[G->RunwayCount][j] = G->BaseLL[ofs][j];
	    for (j=0;j<7;j++) G->RunwayData[G->RunwayCount][j+2] = tokf[j];
	    G->RunwayBase[G->RunwayCount] = ofs;

	    fprintf(GS2CfgPL,"RWY LOADED: %s\'s %s END1(%.0f, %.0f) END2(%.0f, %.0f) PAPI=%.0f VASI=%.0f ALT=%.0f\n", G->BaseName[ofs], G->RunwayName[G->RunwayCount], 
		    G->RunwayData[G->RunwayCount][2], G->RunwayData[G->RunwayCount][3], G->RunwayData[G->RunwayCount][4],
		    G->RunwayData[G->RunwayCount][5], G->RunwayData[G->RunwayCount][6], G->RunwayData[G->RunwayCount][7],G->RunwayData[G->RunwayCount][8]);
	    runwayFound = true;
	    G->RunwayCount++;
	    continue;
	  }

	  if (_stricmp(tok,"GLIDESLOPE")==0)
	  {
// Parsing GLIDESLOPE {gsfilname} "gs description"
// e.g.    GLIDESLOPE XR "XR Series"

      if (!ParseString(&bp,&strtok)) goto badparse;
      if (strlen(strtok)>31) goto badparse;

      if (!LoadPreferredGlideslopeConfig(strtok)) goto badparse; // if it loads, then it's good!

      if (!ParseQuotedString(&bp,&tok)) goto badparse;
      if (strlen(strtok)>31) goto badparse;
      if (G->GSfileCount >= G->GSFILE_LIMIT) goto badparse;

      strcpy(G->GSfileName[G->GSfileCount],strtok);
      strcpy(G->GSname[G->GSfileCount],tok);

	    fprintf(GS2CfgPL,"GLIDESLOPE LOADED: %s (%s)\n", G->GSname[G->GSfileCount], G->GSfileName[G->GSfileCount]);
	    gsFound = true;
      G->GSfileCount++;
	    continue;
	  }

	  if (!_stricmp(tok,"PREFS"))
	  {

  // Parsing PREFS {mode-L} {mode-R} {mode-X} {units}        {rwy}   {glideslope}
  // e.g.    PREFS VSIT     HSIT     DATA        {US | METRIC}  "KSC33" XR

	    if (prefsFound) goto badparse;

      for (int i=0;i<3;i++) {
 	      if (!ParseString(&bp,&tok)) goto badparse;
	      modeTok[i] = (!_stricmp(tok,"VSIT"))? 1 :
                 (!_stricmp(tok,"TAPE"))? 2 :
                 (!_stricmp(tok,"DATA"))? 3 :
                 (!_stricmp(tok,"HSIT"))? 4 :
                 (!_stricmp(tok,"DIAG"))? 5 :
                 (!_stricmp(tok,"DEOR"))? 6 :
                 (!_stricmp(tok,"1"))? 1 :
                 (!_stricmp(tok,"2"))? 2 :
                 (!_stricmp(tok,"3"))? 3 :
                 (!_stricmp(tok,"4"))? 4 :
                 (!_stricmp(tok,"5"))? 5 :
                 (!_stricmp(tok,"5"))? 6 : 7;
        if (modeTok[i]==7) goto badparse;
      }

	    if (!ParseString(&bp,&tok)) goto badparse;
	    if (_stricmp(tok,"US")==0) {
		    unitstok = true;
	    } else if (_stricmp(tok,"METRIC")==0) {
		    unitstok = false;
	    } else goto badparse;
	    if (!ParseQuotedString(&bp,&strtok)) goto badparse;
	    for (ofs=0; (ofs<G->RunwayCount) && (_stricmp(strtok,(G->RunwayName[ofs]))!=0) ; ofs++) {}
	    if (ofs==G->RunwayCount) goto badparse;
	    if (!ParseString(&bp,&tok)) goto badparse;

      if (gsFound) {
        for (j=0; j<G->GSfileCount; j++) {
          if (!_stricmp(tok,G->GSfileName[j])) break;
        }
        if (j<G->GSfileCount) {
          LoadPreferredGlideslopeConfig(tok);
          G->GSfile = j;
        } else goto badparse;
      } else goto badparse;


	    G->ParamsModeL = (modeTok[0]<1)? 1 : (modeTok[0]>G->maxMod) ? G->maxMod : modeTok[0];
	    G->ParamsModeR = (modeTok[1]<1)? 1 : (modeTok[1]>G->maxMod) ? G->maxMod : modeTok[1];
	    G->ParamsModeX = (modeTok[2]<1)? 1 : (modeTok[2]>G->maxMod) ? G->maxMod : modeTok[2];
	    G->ParamsUnits = unitstok;
	    G->ParamsRwy = ofs;
      G->runway = ofs;
	  
	    fprintf(GS2CfgPL,"PREFS LOADED: Mode=%i/%i/%i Units=%s Runway=%s Glideslope=%s\n", G->ParamsModeL,G->ParamsModeR,G->ParamsModeX, (G->ParamsUnits?"US":"METRIC"), G->RunwayName[G->ParamsRwy], tok );
	    G->BaseCount++;
	    prefsFound = true;
	    continue;
		
     }


badparse:
   fprintf(GS2CfgPL,"Bad parse, ignored line>> %s", bufcpy);
   fprintf(GS2CfgPL,"(Check for typos, base not previously defined, base>32 chars, runway >12 chars, >64 bases, > 128 rwys, >1 prefs line, etc.)\n\n");
  }

  if (!feof(GS2cfg)) {
    fprintf(GS2CfgPL,"Bad read on GS2.cfg\n");
    LoadDefaultConfig();
    LoadDefaultGlideslopeConfig();
  } else if ((!prefsFound)||(!baseFound)||(!runwayFound)||(!gsFound)) {
    if (!prefsFound) fprintf(GS2CfgPL,"No PREFS found ... defaulting to Default Config");
    if (!baseFound) fprintf(GS2CfgPL,"No BASE found ... defaulting to Default Config");
    if (!runwayFound) fprintf(GS2CfgPL,"No RUNWAY found ... defaulting to Default Config");
    if (!gsFound) fprintf(GS2CfgPL,"No GLIDESLOPE found ... defaulting to Default Config");
    LoadDefaultConfig();
    LoadDefaultGlideslopeConfig();
  } else {
    fprintf(GS2CfgPL,"Successfully parsed GS2.cfg\n");
	}

  fclose(GS2CfgPL);
  fclose(GS2cfg);

  return;
}



Enjoy!

Woo :blink:

Steam coming out of both ears now, that its complicated stuff. I sorta follow whats going on in the first code block you posted, but I don't get how the actual distinguishing between character, double, int, etc. happens, because the functions for parsing already know what input they'll be receiving. I will figure this out, but you wont be offended if I use Enjos method below? It would appear to be a call to a similar code set that C++ has defined in its standard library, but I'll have to check to see what it does exactly...

In C++, you don't need pointers for purposes other than polymorphic calls, which you don't use, and that's only if you can't use references. If you need dynamic memory, use STL. Tell me what's your task and I'll tell you what to use.


PHP:
string inputVar;
double mass;
cout << "Enter mass\n";
cin >> inputVar;
istringstream ss;
ss.str(inputVar);
if (ss >> mass)
{
 // work with mass
}
else
{
 cout << "Please input a number" << endl;
}

Well Im not sure if I'll just skip over the section on pointers, I would like to be able to say that I read the whole tutorial once I'm done, so I'll continue to slog away anyways. Thanks for the code fragment there, I'll see how that works for my purposes.

Never seen that before! What version of visual studio are you using? Here's something to try - go to file -> new project and create an 'empty project'. When your blank project has been created, right click on 'source files' on the left, and add a new .cpp file (doesn't matter what you call it). Then paste your code into that new file, change it to multi-threaded as I said before, and compile again. I always create an empty project when I start something new, and it seems to compile fine for me.

Hmmm, still no dice, although Im glad to see the thing compile in a blank project, no need to worry about setting up the right solution in MSVC++ (2010 version). The program still wants the MSVCR100.dll, but when you say set the code generation to multi-threaded, I'm not sure what that means. My four options for the Runtime Library setting are:

Multi-threaded (/MT)
Multi-threaded Debug (/MTd)
Multi-threaded DLL (/MD)
Multi-threaded Debug DLL (/MDd)

Howdy. Perhaps you've figured this out already, apologies if this is the case.

For this sort of thing, rather do everything in one case:

Code:
string exit = "EXIT";
string continue = "CONTINUE";
string yes = "YES";

Then when you need to compare input to those, you convert whatever the user typed to uppercase. Java has a function on the String class, I can't remember now what C++ uses but there will be some super-simple way to do it. If you want to be thorough, you also trim the user's input string, so if someone accidentally adds a space on either end of their input, your comparison still works. I always use upper case, but lower case will work out the same.

This is more robust and leads to a LOT fewer lines of code & comparisons. Which will make you code fewer bugs.

---------- Post added at 14:09 ---------- Previous post was at 14:05 ----------

Also I take it you've made a bunch of changes based on the fact that there's been 2 pages worth of conversation :)

Would you mind posting updated code?

Okaay, so switching the users input to uppercase would be great, but how exactly can I do that?

Yes, there has been a lot of discussion, but I'm not exactly sure what to do with the program right now, since I'll have to test some things first, but I can already see a few improvements coming.

Would be a rather near jump given that it is close to the topic of discussing a learner's code. But I see what you mean.

I second Johan's call for an updated version of the code, though. Seeing what progress Bruce made should be interesting.

:lol: I just finished reading the comments, and there are already calls for an update. Its good to be wanted though :thumbup:.

I figure I'll implement that parser fix, then maybe add in a calculator for 2-stage vessels. Eventually I should be able to create a mode that calculates DeeVee for n stages using some sort of do while loop, but that will need some time to be thought about.

On the topic of gotos, I would argue they can be used, but the philosophy behind their use should be "sparingly, and strategically". My first version with the gotos was horrendous, just a messy pile of code with little modularity or usefulness. Goto can still be used effectively though, just by using it to redirect to key areas of the code that can branch out from there using more elegantly written code.
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Woo :blink: Steam coming out of both ears now, that its complicated stuff. I sorta follow whats going on in the first code block you posted, but I don't get how the actual distinguishing between character, double, int, etc. happens, because the functions for parsing already know what input they'll be receiving. I will figure this out, but you wont be offended if I use Enjos method below? It would appear to be a call to a similar code set that C++ has defined in its standard library, but I'll have to check to see what it does exactly...

It's your code - so no offense at all if you choose any method you prefer! Enjo's a more natural C++ guy, and I'm a more natural C guy with classes. The difference being that Enjo is very comfortable with the standard template libraries, whereas I still treat them with suspicion :). My code is being used to code defensively for crap sent in through a scenario cfg file, where I *expect* a type of input, but am suspicious that I will get junk, so I check every character. I'm sure Enjo's solution is way more elegant, but hey!


Well Im not sure if I'll just skip over the section on pointers, I would like to be able to say that I read the whole tutorial once I'm done, so I'll continue to slog away anyways. Thanks for the code fragment there, I'll see how that works for my purposes.


Pointers and references ... always worth taking the time to understand these as much as you can. C guys are much more into pointers, whereas C++ guys like references. I'm kind of in between the two!

Hmmm, still no dice, although Im glad to see the thing compile in a blank project, no need to worry about setting up the right solution in MSVC++ (2010 version). The program still wants the MSVCR100.dll, but when you say set the code generation to multi-threaded, I'm not sure what that means. My four options for the Runtime Library setting are:

Multi-threaded (/MT)
Multi-threaded Debug (/MTd)
Multi-threaded DLL (/MD)
Multi-threaded Debug DLL (/MDd)

MSVCR100.dll has nothing to do with those multi-threading options (which BTW are totally not needed for you code until you are coding multiple execution threads - i.e. later). It's just the VC++ Release 2010 runtime DLL. You can statically link this into your code, but you generally do not want to do this as you hard-compile in runtime vulnerabilities that may need critical patching later. So it's best to shrug your shoulders and say - you need a VC redistributable install to run this, so do it already!


On the topic of gotos, I would argue they can be used, but the philosophy behind their use should be "sparingly, and strategically". My first version with the gotos was horrendous, just a messy pile of code with little modularity or usefulness. Goto can still be used effectively though, just by using it to redirect to key areas of the code that can branch out from there using more elegantly written code.

If you look at my example, I had copious amounts of gotos all heading to badparse:. I felt that it was clean to keep the main control loop parsing the input, and then jump out each time I rejected an input line. I've also done this with try-catch-throw in other code and I think I prefer that style instead. But just wanted to throw that out as an example of non-main control loop branching where goto may be less ugly.
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
Okaay, so switching the users input to uppercase would be great, but how exactly can I do that?

For example with this (std::transform is from <algorithm>, toupper is from <cctype> or <ctype.h>):
Code:
std::transform (read_string.begin (), read_string.end (), read_string.begin (), toupper);
 
Top