Archived

This topic is now archived and is closed to further replies.

nookiepl

Parsing a line ?

Recommended Posts

Hi i''m trying to make a console in my program, but im very lame on C++ for example we have line like this: set vid_mode 1 how to parse teh string that, first word is a command second, var, and the third one is value ?? and another example: say i''m lame How to make parsing code to work on both examples ? becouse teh first one is with spaces between every word, and in the second i want to rcognize function say, and the rest is teh string (with spaces) that it should display ?? Please help Thanks in advance Nookie

Share this post


Link to post
Share on other sites
Well you are probably going to want to start with some form of a variable system. CVARs, in quake-talk. They need to contain the data and the variable name (as known by the console). Usually people use a linked list for this, but arrays of structs work too.

Next you oughta try parsing the commands. Tokenize it first (aka do a large switch command or something on the first word to find out the command, and then set some variable). Then if you find that the command is set, then read the first parameter, the variable name, and find what data they are refering to. Then read the last parameter, the value, and set the variable to it. If you want to be able to set variables to variables, you will have to repeat the variable search.

All the while make sure to have error checking (aka command existing, variable existing, valid value to set to). Not too difficult, really! The trick is making a good one...

L8r,
The Rainmaker

Share this post


Link to post
Share on other sites
Try something like this:

enum all_my_commands_e
{
  COMMAND_SET=0,
// other commands...
};

int TokenizeCommand(char *command)
{
  if(strcmp(command,"set")==0)
  {
    return COMMAND_SET;
  } // else if for other commands
  return -1; // errornous
}

char* GetCommand(char *input)
{
  int i=0;
  char *pChar=input;
  char ret[256];
  memset(ret,0,sizeof(char)*256);
  while(pChar && pChar != '' '')
  {
    ret[i++] = pChar;
  }
  return ret;
}

void ParseString(char *input)
{
  int command;
  command = TokenizeCommand(GetCommand(input));
// ...
}

something like that. Not sure if that would work, but probably would.

L8r,
The Rainmaker

Share this post


Link to post
Share on other sites
straight C++


  
#include <sstream>

#include <string>


struct command
{
std::string command;
std::string variable;
long l;
};

command parse( std::string& line )
{
// create a stream for reading from the string

std::stringstream ss( line );
command com;
ss >> com.command >> com.variable >> com.l;
return com;
}


straight C


  
#include <stdio.h>


struct command
{
std::string command;
std::string variable;
long l;
};

struct command
parse( char* line )
{
struct command com;

sscanf( line, "%s %s %d", &com.command, &com.variable, &com.l

return com
);


Using boost::tokenizer and boost::lexical_cast


  
#include <vector>

#include <string>

#include <boost/tokenizer.hpp>


typedef vector<std::string> command;

command parse( std::string& line )
{
boost::tokenizer tok( line );
return command( tok.begin(), tok.end() );
};

// com is now a vector of strings

// you can access each word by simple indexing

// and use boost::lexical_cast to convert to

// numerical values. In your case :


command com = parse( line );
long l = boost::lexical_cast<long>( com[2] );

// That way, each command can take whatever parameter

// it wants.






Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]

Share this post


Link to post
Share on other sites
And for boost::tokenizer to process quoted strings ("say"), here is my very own tokenizing function :


    
#ifndef BOOST_MSVC
template <typename Char,
typename Traits = typename std::basic_string<Char>::traits_type >
#else
template <typename Char,
typename Traits = std::basic_string<Char>::traits_type >
#endif
class quoted_separator
{
typedef std::basic_string<Char,Traits> string_type;
public:
explicit quoted_separator() : m_quoted( false ) {};

inline bool is_quote( Char q ) { return q == '\"'; };

void reset() { m_quoted = false; }

template <typename InputIterator, typename Token>
bool operator()(InputIterator& next, InputIterator end, Token& tok)
{
tok = Token();

// skip past all dropped_delims

if (!m_quoted)
for (; next != end && std::isspace(*next); ++next)
{ }

if (next == end)
return false;
else if( next!= end && is_quote(*next) )
{
m_quoted = !m_quoted;
++next;
}

if( m_quoted )
for(; next != end && !is_quote(*next); ++next )
tok += *next;
else
for(; next != end && !is_quote(*next) && !isspace(*next); ++next )
tok += *next;

if( next!= end && is_quote(*next) )
{
m_quoted = !m_quoted;
++next;
}

return true;
}

private:
bool m_quoted;

};


which you just feed to boost::tokenizer as a template parameter.


  
command parse( std::string& line )
{
boost::tokenizer<quoted_separator<char> > tok ( line );
return command( tok.begin(), tok.end() );
}


Enjoy

Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]


[edited by - Fruny on June 9, 2002 6:42:25 PM]

Share this post


Link to post
Share on other sites
I would prob. build a recursive descent parser.
Thoose are pretty fast/easy to code & work nice.
Once you get your grammar going it''s very easy to expand it.

The idea is that you have one functionA that "looks" for a "set"
inside functionA you look for "Vid_Mode"...inside function Vid_Mode you look for "Nummber" etc..etcc..

Share this post


Link to post
Share on other sites