storing static data of variable types

G

Gernot Frisch

Hi,

I've got to write a BASIC to C++ converter and came across the problem of
the DATA statement.

I must provide a way of storing:
DATA 5.123, "abc", ...
in C++.

my first guess was this:

struct
{
double* pD;
const char* pC;
} str[2]={
{NULL, "xy"},
{&123.4, NULL},
};


but &123.4 is not possible. Now, having temporary global variables for this
doesn't make me too happy either.

Is there a "clean" way of doing this?
 
I

Ian Collins

Gernot said:
Hi,

I've got to write a BASIC to C++ converter and came across the problem
of the DATA statement.

I must provide a way of storing:
DATA 5.123, "abc", ...
in C++.

my first guess was this:

struct
{
double* pD;
const char* pC;
} str[2]={
{NULL, "xy"},
{&123.4, NULL},
};


but &123.4 is not possible. Now, having temporary global variables for
this doesn't make me too happy either.

Is there a "clean" way of doing this?
Store the values as strings and convert then back as required?
 
M

Michael DOUBEZ

Gernot Frisch a écrit :
Hi,

I've got to write a BASIC to C++ converter and came across the problem
of the DATA statement.

I must provide a way of storing:
DATA 5.123, "abc", ...
in C++.

my first guess was this:

struct
{
double* pD;
const char* pC;
} str[2]={
{NULL, "xy"},
{&123.4, NULL},
};


but &123.4 is not possible. Now, having temporary global variables for
this doesn't make me too happy either.

Is there a "clean" way of doing this?

Directly stores the value instead:

struct
{
double pD;
const char* pC;
}str[2]={
{NULL, "xy"},
{123.4, NULL},
};

Michael
 
G

Gernot Frisch

Directly stores the value instead:

struct
{
double pD;
const char* pC;
}str[2]={
{NULL, "xy"},
{123.4, NULL},
};


First I thought I'd store twice the ammount hten. But thinking of it, my way
I'd store the number _plus_ a pointer to it. I'm so stupid.
Thank you for showing me :)
 
M

Michael DOUBEZ

Gernot Frisch a écrit :
Directly stores the value instead:

struct
{
double pD;
const char* pC;
}str[2]={
{NULL, "xy"},
{123.4, NULL},
};


First I thought I'd store twice the ammount hten. But thinking of it, my
way I'd store the number _plus_ a pointer to it. I'm so stupid.
Thank you for showing me :)

If memory space is an issue, you could use a union (and a type tag to
retrieve the relevant information).

It is common in many interpreters written in C:
struct
{
int type; //give the type of data
union
{
const char* m_string;
double m_double;
long m_integer;
//...
} data;
}

Nowadays, I think there is Boost.Variant that simplifies this much but I
have no experience with it. Perhaps worth a look.

Michael
 
M

Michael.Boehnisch

I've got to write a BASIC to C++ converter and came across the problem of
the DATA statement.
I must provide a way of storing:
DATA 5.123, "abc", ...
in C++. [..]

but &123.4 is not possible. Now, having temporary global variables for this
doesn't make me too happy either.

Is there a "clean" way of doing this?

Try this approach:

#include <list>
#include <string>
#include <stdexcpt>

class Data {
public:

typedef enum { String, Double } Type;

Data( const std::string& s ) : str( s ), dbl( 0 ), type( String )
{}
Data( const double d ) : str( "" ), dbl( d ), type( Double ) {}

class Exception : public std::exception {
public:
Exception( const std::string& s ) : std::exception( s.c_str() )
{}
};

Type GetType() const { return type; }

const std::string& GetSValue() const {
if ( GetType() == String ) return str;
else throw Exception( "DATA type is String" );
}

double GetDValue() const {
if ( GetType() == Double ) return dbl;
else throw Exception( "DATA type is Double" );
}

private:

std::string str;
double dbl;
Type type;

};

class Repository : private std::list<Data> {
public:
Repository( const Data* beg, const Data* end )
: std::list<Data>( beg, end ), current( begin() )
{}

const Data& Read() {
if ( current == end() ) Restore(); // or throw exception
return *(current++);
}

void Restore() { current = begin(); }


void Restore( const int lineno ) {
// left as an exercise :) you need another private
// container member, e.g.
// std::map<unsigned int, std::list<Data>::const_iterator>
// recording the line numbers and the start of the corresponding
// DATA content.
}

private:
std::list<Data>::const_iterator current;

};

.....

DATA 123.4, "xy" translates to:

static Data data[] = { Data( 123.4 ), Data( "xy" ) /* , ... */ };
Repository MyData( &data[0], &data[sizeof(data) / sizeof(Data)] );

You may want to collect all DATA statements in your translator before
you write out the generated code.

Each READ X translates to:
double X;
/* ... */
X = MyData.Read().GetDValue();

Each READ Y$ translates to:
std::string Y;
/* ... */
Y = MyData.Read().GetSValue();

Violation of data types result in an exception - just like BASIC gives
an error.

Each RESTORE translates to:
MyData.Restore();

best,

Michael
 
G

Gernot Frisch

DATA 123.4, "xy" translates to:

static Data data[] = { Data( 123.4 ), Data( "xy" ) /* , ... */ };
Repository MyData( &data[0], &data[sizeof(data) / sizeof(Data)] );


I did something similar already. Thank you for your time and help.
For the Read, I just overloaded 2 functions:
void READ(MyNumber& dbl);
void READ(MyString& str);
 

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,995
Messages
2,570,235
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top