Archived

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

Is this a good idea for scripting language stack?

This topic is 5272 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi I was thinking what kind of stack to have for my scripting language? So far Ive have just simbly used vector vInts; for stack of all integer values... But now im planning to have stack what could have any type of c++ classes. So can you make stack wich could have random access to all kind of vars it holds? kinda like void vector... I know that access it randomly would be quite tricky becose you can''t asume getting third var by: stack[3] but that can be solved counting the pos before execution. language is c++ coding is the game.

Share this post


Link to post
Share on other sites
You could simply have a stack of bytes, and make your push function something like this:

int CStack::Push(unsigned char *p, size_t size)
{
if(m_SP + size > m_stackSize)
{
// Return an error or allocate more memory for stack here

}

for(int i=0;i<size;i++)
m_stackArray[m_SP++] = *(p++);
return 0;
}

I haven't tested this code, but I'll explain what it's supposed to do. When you want to push something, pass the address of the object, along with its size, like pStack->Push(&obj, sizeof obj);
First, the function checks if the current size of the stack plus the size of the new object would make the stack overflow (all member vars are prefixed with 'm_'), and takes action accordingly.
Then it loops through the entire object, stores the byte the pointer you passed is currently pointing to on the stack, and increments the pointer and stack pointer.


"For crying out loud, she has fishes coming out of her head on either side. How can you find this hot?!"

"If anyone sees a suspicious, camouflaged factory being carried across the desert, they should report it immediately ."


[edited by - Valderman on July 6, 2003 9:44:56 PM]

Share this post


Link to post
Share on other sites
Man that''s a lot of overhead for a stack push... which is something a VM will do alot of.

On CPU''s with a MMU, you allocate the stack one page at a time by handling the access violation that occurs when you exceed your bounds. However that requires privileged system access (kernel mode).


Oh well, for lack aof a better (user mode) way to do it, just like Valderman suggest, except I''d make a template function:


template<typename T>
void Push(const T& blob)
{
size_t new_size = this->size + sizeof(T);
if(new_size>this->max_size)
throw stack_overflow;

memcpy(&this->buffer[this->size], &blob);
this->size = new_size;
}

Share this post


Link to post
Share on other sites
My scripting language currently only supports ints, floats, and strings, and is fully procedural. When I add objects and classes to the language, they''ll probably go through some sort of registration process and receive an object id #. That way all object references can be represented by ints.

I''ve wrapped all 3 data types into a single unified type called "value", and provided overloaded operators for pretty much any operation you could want to do on it.

The runtime stack is simply a std::stack<value> right now. I haven''t done any serious performance tests, but for now it is adequate.

Share this post


Link to post
Share on other sites
So like this?:



char* buffer[256];
int spos = 0;

template<typename T>void Push(const T& blob)
{
memcpy(&buffer[spos], &blob, sizeof(T));

spos += sizeof(T);
}

int main()
{
string str = "helloy";
vector<int> vInts;

Push(vInts);
Push(str);
}


But how can I get the values from stack if I know starting point of the value in stack and sizeof it?


Share this post


Link to post
Share on other sites
Or what about this then:

void* svars[256];
int spos = 0;

template<class T> void Push(const T var)
{
svars[spos] = new T;
*(T*)svars[spos] = var;
spos += sizeof(T);
}

template<class T> void GetVar(T& var,int pos)
{
var = *(T*)svars[pos];
}

int main()
{
string str = "helloy";

Push(1234567);
Push(str);
Push(1+1);

int i;
string s;
GetVar(i,0);
GetVar(s,4);

cout<< i <<endl;
cout<< s <<endl;

GetVar(i,20);
cout<< i <<endl;

return 1;
}


Now that code works very nicely, but it''s doesn''t actualy solve anything if we are thinking of something better than difrend stack for each type.

And what''s really bad whit that is that I have to use GetVar whit parameter wich takes the value (return would be better). And offcourse I could return the value but I would still have to insert the parameter so compiler would know what type we are getting?

tips would be higly apreciated.

Share this post


Link to post
Share on other sites
The function called does know what types it is receiving. You use a pass-by-address function like you have or something like this:


template<typename T>
const T& Pop()
{
size_t new_size = this->size - sizeof(T);
if(new_size > 2147483648)
throw stack_underflow;

this->size = new_size;
return *reinterpret_cast<T*>(&this->buffer[this->size]);
}

void Test(MyStack& stack)
{
int i = stack.GetVat<int>();
float f = stack.GetVar<float>();
}


You could overload the << and >> operators with a template too. Then you don''t have to tell it what the type T is.


template<typename T>
MyStack& operator<<(MyStack& stack, const T& t)
{
stack.Push(t);
return stack;
}

template<typename T>
MyStack& operator>>(MyStack& stack, T& t)
{
t = stack.Pop<T>();
return stack;
}


I''ve used a mechanism much like this, and I also used some meta-templates and Loki''s Typelist to automate the detection of the function signature and invoke the function after extracting the parameters from the scripting stack.

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor
The function called does know what types it is receiving. You use a pass-by-address function like you have or something like this:


template<typename T>
const T& Pop()
{
size_t new_size = this->size - sizeof(T);
if(new_size > 2147483648)
throw stack_underflow;

this->size = new_size;
return *reinterpret_cast<T*>(&this->buffer[this->size]);
}

void Test(MyStack& stack)
{
int i = stack.GetVat<int>();
float f = stack.GetVar<float>();
}


You could overload the << and >> operators with a template too. Then you don''t have to tell it what the type T is.


template<typename T>
MyStack& operator<<(MyStack& stack, const T& t)
{
stack.Push(t);
return stack;
}

template<typename T>
MyStack& operator>>(MyStack& stack, T& t)
{
t = stack.Pop<T>();
return stack;
}


I''ve used a mechanism much like this, and I also used some meta-templates and Loki''s Typelist to automate the detection of the function signature and invoke the function after extracting the parameters from the scripting stack.


Thanks Magmai Kai Holmlor.
this solution is very neat:
stack.GetVat();
Though last time I tryed to use shometing like that I got error that T could''t be determinated. However will be testing .

Share this post


Link to post
Share on other sites