Preprocessor & while conditie modificatie

Status
Niet open voor verdere reacties.

That Guy

Meubilair
Lid geworden
28 nov 2006
Berichten
5.010
Hello!,

Ik ben al een tijdje bezig met een lexer te schrijven voor een javascript/c/c++ achtige taal. Nu wou ik m'n subroutine om getallen te lexen eens wat korter/mooier/duidelijker maken, dus dacht ik, waarom niet wat klooien met de pp. Zie hier:

[CPP]Token * numeric_token()
{
char current_character;
std::string number;
bool fraction = false,
is_hex = false;

#define IS_ALLOWED_CHARACTER(c) ( isdigit(c) )

while( chars_available() && (current_character = get_char()) && IS_ALLOWED_CHARACTER(current_character) )
{
buffer_index++;
number += current_character;

#define IS_ALLOWED_CHARACTER(c) ( isdigit(c) || c == '.' || c == 'x' )

if( current_character == 'x' )
{
if( is_hex ) // "0x" en dan nog ergens een x is geen valide hex nummer
{
throw Exception("invalid number: '" + number + "'");
}else{
is_hex = true;
#define IS_ALLOWED_CHARACTER(c) ( isxdigit(c) )

}
}

if( current_character == '.' )
{
if( fraction ) // als het een float is en er komt een punt achter, zal dat vast een methode zijn ( e.g. 3.14.toString() )
{
break; // done
}else{
fraction = true;
#define IS_ALLOWED_CHARACTER(c) ( isdigit(c) )

}
}
}

#undef IS_ALLOWED_CHARACTER

return new Token( '...' );
}[/CPP]
(lichtelijk gestript)

Het idee is dat 'ie de volgende 'type' getallen parsed:
Code:
3 (int)
3.14 (float)
0x42 (hex)
Nu is het probleem... het werkt niet. Kan het kloppen dat de #defines die IN de while zitten, niet uitgevoerd worden? Iemand een idee?

Groet en alvast bedankt.
 
Laatst bewerkt:
Om het iets te verduidelijken: een getal als 345 pakt 'ie goed. Echter, 0xABCD pakt 'ie als getal 0 en dan de string xABCD (welke in een andere subroutine wordt geparsed - hij ziet de 'x' niet als deel van het getal, het breekt dus uit de while loop op de while(...) conditie. Hij pakt de nieuwe #define dus niet?).
 
Volgens mij ben je nog niet helemaal mee met wat (en wanneer) de preprocessor iets doet.

In het builden van een executable vanuit C++ sources heb je meestal de volgende stappen:
  1. Code schrijven in header en source files
  2. De preprocessor verwerkt alle source files, lijn per lijn. Bij sommige precompilers kan je vragen dat dit resultaat naar een bestand wordt weggeschreven (meestal extentie *.i)
  3. De compiler verwerkt het resultaat van de preprocessor, per originele source file ontstaat een object file (meestal extentie *.o)
  4. De linker combineert al deze verschillende object files in een executable, jouw programma
Zoals je ziet grijpt de preprocessor in alvorens je code wordt gecompileerd; aangezien ik nu niet de mogelijkheid heb om jouw fragment door een echte preprocessor te halen en je de output te tonen, heb ik je fragment even manueel ge-edit naar wat ongeveer het resultaat van de preprocessor wordt, en dus naar welke code er gecompileerd zal worden:
[CPP]Token * numeric_token()
{
char current_character;
std::string number;
bool fraction = false,
is_hex = false;

//volgende lijn wordt verwijderd door de preprocessor, aangezien dit nu verwerkt is
//#define IS_ALLOWED_CHARACTER(c) ( isdigit(c) )
//vanaf dit punt gaat de preprocessor elke keer hij de identifier tegenkomt de gewenste replace uitvoeren

//while( chars_available() && (current_character = get_char()) && IS_ALLOWED_CHARACTER(current_character) )
//werd vervangen door
while( chars_available() && (current_character = get_char()) && ( isdigit(current_character) ) )
{
buffer_index++;
number += current_character;

//strict genomen geeft je preprocessor hier normaalgezien een warning op, je mag een term niet herdefiniëren
//#define IS_ALLOWED_CHARACTER(c) ( isdigit(c) || c == '.' || c == 'x' )
//afhankelijk van welke preprocessor je gebruikt, kan het zijn dat de definitie nu vervangen is door de nieuwe definitie

if( current_character == 'x' )
{
if( is_hex ) // "0x" en dan nog ergens een x is geen valide hex nummer
{
throw Exception("invalid number: '" + number + "'");
}else{
is_hex = true;
//strict genomen geeft je preprocessor hier normaalgezien een warning op, je mag een term niet herdefiniëren
//#define IS_ALLOWED_CHARACTER(c) ( isxdigit(c) )
//afhankelijk van welke preprocessor je gebruikt, kan het zijn dat de definitie nu vervangen is door de nieuwe definitie
}
}

if( current_character == '.' )
{
if( fraction ) // als het een float is en er komt een punt achter, zal dat vast een methode zijn ( e.g. 3.14.toString() )
{
break; // done
}else{
fraction = true;
//strict genomen geeft je preprocessor hier normaalgezien een warning op, je mag een term niet herdefiniëren
//#define IS_ALLOWED_CHARACTER(c) ( isdigit(c) )
//afhankelijk van welke preprocessor je gebruikt, kan het zijn dat de definitie nu vervangen is door de nieuwe definitie
}
}
}

//#undef IS_ALLOWED_CHARACTER
//indien er voorbij deze regel nog de identifier IS_ALLOWED_CHARACTER staat zal hij niet meer worden vervangen
return new Token( '...' );
}[/CPP]
Ik heb de stukken die preprocessor uitvoert express helemaal links gealigned. Het is deze code die naar de compiler wordt gestuurd en dus uiteindelijk uitgevoerd zal worden. Waar jouw misvatting zat is dat de preprocessor lijn per lijn werkt en zich niets aantrekt van jouw code-structuur.

De resulterende code zal in de while-lus dus enkel controleren of current_character een digit is en niks anders.
 
Hi Johantrax,

Bedankt voor je uitleg. Het is nu duidelijk! Overigens wel een beetje een derp aan mijn kant, het heet immers de preprocessor... :)
Helaas, want ik vond 't wel een subtiele oplossing. :P
 
Laatst bewerkt:
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan