2

I have a file like this

EntityName Jaws
{
  Animation WALK
  {
    NumberOfFrames 9
    DirectionOfSprite L
    DirectionGenerate LR
    FPS 9
  }

  Animation IDLE
  {
    NumberOfFrames 6
    DirectionOfSprite L
    DirectionGenerate LR
    FPS 9
  }
  .......
  .......
}

How do I parse this file in this struct

struct AnimationData
{
  string animationName;
  int noOfFrames;
  eAnimationDataDirection direction;
  int FPS;
};

struct EntityAnimationData
{
  string entityName;
  vector<AnimationData> animationData;

  string getSpriteResourceName(AnimationData animationData, int frameNumber);
};

I want to store this data into the struct. How do I go about to get a clean solution? I've read the basic reading of a file.

This is what I've tried

EntityAnimationData parseAnimationData(const char* filename)
{
  EntityAnimationData data;
  ifstream file;
  file.open(filename);
  char output[128];
  string op;
  if (file.is_open())
  {
    while (!file.eof())
    {
      file >> output;
      if(strcmp(parameter,AD_ENTITY_NAME.c_str())==0)
      {
        file >> output;
        data.entityName = output;
        cout<<data.entityName<<endl;
        do
        {
          file >> output;
          cout<<output<<endl;
        }while(strcmp(output,"}")!=0);
      }
    }
  }
  file.close();
  return data;
}
Jeffrey Chen
  • 237
  • 1
  • 4
  • 17

3 Answers3

6

If this is for a game you're making, I would consider changing the input file format details. If you use an existing file format, you could use a library to dramatically simplify parsing.

For example, this same data could easily be stored as XML, which would allow you to use an XML parser (such as TinyXML-2) to read the data, and probably make creation of the file simpler, as well. It also would make it simpler to add more robust handling of formatting issues, such as extra whitespace, etc.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Can u suggest me some links to a c++ xml parser library. – Jeffrey Chen May 16 '12 at 23:36
  • @JeffreyChen: He linked you to one. Also, there are [these](http://stackoverflow.com/questions/9387610/what-xml-parser-should-i-use-in-c) – Nicol Bolas May 16 '12 at 23:37
  • @JeffreyChen Nicol's link is great - TinyXML-2 is very nice if you just have simple requirements, which, given you were going to write your own parser, I'm guessing is the case. It's super-lightweight and easy to use in that scenario... – Reed Copsey May 16 '12 at 23:39
  • Interesting - why the downvoting? – Reed Copsey May 17 '12 at 01:14
  • After stubbornly trying to do parsing by myself which later got complicated and Decided to use tinyxml2 .. well it works nicely !! – Jeffrey Chen Jun 09 '12 at 04:31
1

Sans of creating a grammar and using tools like lex/yacc to create a parser for you (the BOOST library has a parser too), you need to read each token (like you are doing now: file >> token -- I would recommend using std::string for the token, not a char array), then compare the token to the expected next token (if it's one of the fixed ones, like EntityName, Animation, {) then assign the value of the token to the appropriate part of the structure. If you need an integer as the next value, you can replace token with the apropriate member of the structure.

Note: If you take this approach, make sure you check for errors at each extraction operation, instead of assuming that the file will always be in the correct format

Attila
  • 28,265
  • 3
  • 46
  • 55
1

If you have a fixed file format, which you don't expect to change then you can do readline followed by if/else. Otherwise writing a parser for this format is pretty simple and provides more flexibility. Below is an example of using AXE parser generator.

Some assumptions: you didn't specify what the names are, I'm using identifier rule (axe::r_ident) in this example, you may change it to whatever suits your needs. I also assume you don't care about spaces, tabs, line ends, so you can use an axe::r_skip rule to skip them all. I assume the numbers you use are decimal.

template<class I>
EntityAnimationData parse(I begin, I end)
{
    EntityAnimationData data;
    AnimationData ad; // temporary

    auto direction = axe::r_lit("LR") | "RL" | 'L' | 'R';

    auto animation_data = "Animation" & axe::r_ident() >> ad.animationName 
        & '{' 
        & "NumberOfFrames" & axe::r_decimal(ad.noOfFrames)
        & "DirectionOfSprite" & direction >> axe::e_ref([&](I i1, I i2)
        {
           std::string dir(i1, i2); // this will be "LR" or "RL" or 'L' or 'R'
           // ad.direction = ...
        })
        & "DirectionGenerate" & direction  >> axe::e_ref([&](I i1, I i2)
        {
           std::string dir(i1, i2); // this will be "LR" or "RL" or 'L' or 'R'
           // ad.direction = ...
        })
        & "FPS" & axe::r_decimal(ad.FPS)
        & '}';

    auto entity_data = axe::r_lit("EntityName") & axe::r_ident() >> data.entityName 
        & '{' 
        & *(animation_data >> axe::e_ref([&](...) { data.animationData.push_back(ad); }))
        & '}'
        & axe::r_end();
    // create a skip rule
    auto data_skip_spaces = axe::r_skip(entity_data, " \t\n");
    auto match = data_skip_spaces(begin, end);
    if(!match.matched)
        throw "format error";

    return data;
}

void foo()
{
   std::string text = "EntityName Jaws\n{\n  Animation WALK\n  {\n    NumberOfFrames 9 ...";
   EntityAnimationData data = parse(text.begin(), text.end());
}
Gene Bushuyev
  • 5,512
  • 20
  • 19