The Dink Network

TDP to the rescue!

November 11th 2003, 09:39 PM
wizardb.gif
merlin
Peasant He/Him
 
Heheh. Well, DesPlesda's DinkC++ creation is done. Here's the nice guide he wrote:

-----BEGIN-----

DinkC++ Guide
Jon Manning

The following will make no sense if you don't know:
1. Programming
2. Dink SmallWood
3. DinkC

Now that that's out of the way:

DinkC++ is a replacement for DinkC. Here's a quick guide to what's new and
what's changed.

All DinkC scripts will work in DinkC++, except those that use the menu system
(which I'm still working on). However, DinkC++ lets you do these too:

1. &dink = "DinkC++ teh pwn";
Variables can be assigned string values as well as integers. Floats are
on the way.
2. &myvariable = "doesn't need to be declared before use!";
Variables do not need to be declared anymore. Referring to a variable
creates it if it doesn't exist already (so typo's become slightly more
of an
issue; but the parser traps attempts to get values from empty variables
so it's not that bad (in fact I think it's better this way (triple
parentheses block!!)))
3. function my_function(&foo, &bar) {
Functions can be given parameters now. DinkC++ also supports variable
length parameter lists; just use '&var = argument;' for any extra
parameters you need:

myfunc("parm 1", "parm 2", "parm 3");

function myfunc(&myparm) { // note only one parm is declared
&myotherparm = argument;
&myotherOTHERparm = argument;
} // &myparm = "parm 1", &myotherparm = "parm2",
&myotherOTHERparm = guess!

'argument' is still very buggy. Don't rely on it, because all it does
it directly pops a value off the stack, and if other operations have
pushed values on, you'll be getting junk in your parameters.

Note that 'void' is valid for a function receiving no parameters, and
'function' has replaced 'void' at the start of a function declaration.
('void' will still work, but since return-type declarators have no
meaning in DinkC++ the keyword 'function' seems more appropriate)
4. function myfunc(void) { return 1337; }
Functions can return values now, be they strings or numbers.
5. &foo, &bar = "dink", "rocks";
Multiple assignment. Hell yeah. Note that a quick way to swap the
values of two variables is &x, &y = &y, &x;. The number of items on either
side can be anything, but they MUST be equal. Too many on the left
hand side will mean getting values that aren't there (or values that
you don't want), while too many on the right will leave values sitting
on the stack, wasting space (which you have a finite amount of; only
255 values can be pushed onto each script's stack, maximum).
6. return "one result", &tworesult, "threeresult", 4;
This works too. To get the results back, do this:

&1, &2, &3, &4 = func(); // which returns 4 values

The same guidelines apply here as multiple variable assignment;
make sure you know exactly how many values are being returned
by the function you're calling.
7. "string" + "plus" + &variable + 1337 + "<- number!"
Strings can be concatenated. DinkC++ automagically handles conversion
between integers and strings: if the first element in an addition
is a string, the result of that addition will also be a string. So:

"foo" + 2 = "foo2"
but: 2 + "foo" = 2 (foo can't be converted to a number)
AND: 2 + "2" = 4
AND: 2 + 2 = 4 (omg)

If you want an addition to result in a string, but also want the
first element to be a number (tuh, some people eh) then do this:

"" + 2 + "2" = "22"

And of course there can be more than two elements in any operation.
8. if (&var1 || &var2 && func(1337))
AND and OR, just like C. Begone, unnecessarily nested if blocks!
9. do, while and for loops are now implemented.
Use them just like in C.
10. And a brand-new parser means you can do shocking things like having
more than one statement per line, having comments on the same line
as statments, or even complex math like 2 + 3 + 42!

Getting a DinkScript working:
There are three standard programs that you'll use.

dinkompile: converts DinkC++ to DinkASM, the low-level stuff that
actually gets run
dinkasm: converts the ASCII DinkASM produced by dinkompile to
binary
dinkparse: runs the thing

A DinkC++ source file ends in .c
A DinkASM source file ends in .s
A compiled DinkC++ file ends in .dpp (Dink++, innit)

dink.c > dinkompile = dink.s
dink.s > dinkasm = dink.dpp
dink.dpp > dinkparse = A running app!

The intermediary step is there so you can have a closer look at what
your program is doing, if you want. And also for debugging.

A .dpp file can be very easily converted to ASCII again, but
converting back to DinkC++ is slightly harder than DinkC's method (byte-pair
encoding? Call that compilation, Seth?! )

What's Coming Next:

- An interactive interpreter (so we don't have to do compilation)
- Optimisation (stack cleanup)
- Something similar to python's 'import' statement, to include libraries
of functions in mid-execution
- Dictionaries (that is, arrays that use keys instead of indices :
&enemy_of["dink"] = &seth; etc)
- Automatic substitution of variable names for values in strings (at the
moment "foo = &foo" will print 'foo = &foo' and not 'foo = 1337')

-- The DinkC++ API --

"Great, Jon, but I want to know how to bung this into my own program, or
maybe even into Dink!"

Really! (Freak.) Then you can use the DinkC++ API to include DinkC++ with
C programs. Anybody who knows the language Lua (http://www.lua.org, you
guy are teh rox) will feel instantly at home. In fact I'll probably
be getting flamed for copying Lua's style soon.

Each script is stored in a DinkC++ state, which is a dynamically allocated
structure that contains the script's symbol table, which handles the variables,
its value stack, where values are exchanged (hehe. stack exchange. hehe), and
the script's call stack, which handles function calling.

To create a state, call dinkc_open(), which returns a pointer to an
allocated dinkc_State structure. To get the script inside the state,
call dinkc_load(dinkc_State*, char*) with the pointer to your state
and the path to your script. To begin executing, just call
dinkc_execute(dinkc_State*) with your state pointer.

You probably won't ever need to modify any of the state itself; a library of
manipulation functions exist to serve. But I'll get to those later.

Now, you're probably asking, "all this is is great, but how do I get DinkC++ to
do something useful? Like, say, call C functions?" It's really (kinda) simple.
Use the dinkc_register function, which I'll explain the usage of in a bit.

To register a C function with DinkC++, it has to be of type dinkc_CFunction,
which is defined as:
typedef int (*dinkc_CFunction) (dinkc_State *D);
That is, a function accepting a pointer to a dinkc_State and returning an int.
(At the moment, the value returned from the function isn't used, but it will be
in the next release. For the moment, get it to return the number of values
returned
by the C function to DinkC++.) Here's an example.

int dink_helloworld(dinkc_State* d) {
printf("Hello, world!\n");
}

To register this function, call dinkc_register, which in this case uses the
arguments:
dinkc_register(my_state, "hello", dink_helloworld);
The parameters for dinkc_register are the state that you want it to
be applied to, the name of the function as it appears to DinkC++, and
finally the function itself. When registered, our Hello, World function
can be called from DinkC++ like so:
hello();
Which outputs to stdout:
Hello, world!

Great, now about paramters. Well, since DinkC++ operates using a value stack,
which pushes and pops string and integers on and off according to the whims
of the fates, or functions, whomever comes first, C functions that want to
talk to DinkC++ have to use the stack too. To get values off the stack, use
these functions:

int dinkc_popint(dinkc_State*) pops an integer off the stack and returns its
value
(conversion of any strings is automagically handled, aren't you lucky)
void dinkc_popstring(dinkc_State*, char*) pops a string off the stack and puts
it into the specified array of characters (I'll convert for you, but I won't
allocate for you)

To get values on the stack:

int dinkc_pushint(dinkc_State*, int) pushes an int
int dinkc_pushstring(dinkc_State*, char*) pushes a string

These functions currently do not return anything at the moment.

Finally, to call a DinkC++ function, use the dinkc_call function:
int dinkc_call(dinkc_State*, char*);
The second parameter is the name of the DinkC++ function. You'll need
to have the proper arguments pushed onto the stack before calling.
Here's an important tip: you need to push the values onto the stack
BACKWARDS. Just like calling a C function from Assembler. This allows easier
implementation of variable-length parameter lists.

DinkC++ API Summary:

dinkc_State* dinkc_open(void); /* create a state */
int dinkc_load(dinkc_State* d, char* path); /* open a file pointer, create the
command list */
int dinkc_execute(dinkc_State* d); /* go! */
int dinkc_pushint(dinkc_State* d, int value); /* push integer */
int dinkc_pushstring(dinkc_State* d, char* value); /* push string */
void dinkc_popvar(dinkc_State* d, char* variable_name); /* pop value into
DinkC++ variable */
int dinkc_popint(dinkc_State* d); /* pops an int or an integer variable's value
from the stack */
void dinkc_popstring(dinkc_State* d, char* destination_string); /* pops a
string from the stack, puts it in destination_string */
void dinkc_register(dinkc_State* d, char* name, dinkc_CFunction function); /*
registers a C function for use in DinkC++ */
int dinkc_call(dinkc_State* d, char* function_name); /* calls a DinkC++
function */

-----END-----

So there you have it folks, an overview of the status of the DinkC++ API. Now, it's up to lazy 'ol me to implement it. Heh. If you desire a copy, you can acquire it from developer's CVS. You can probably get a hold of it from anonymous cvs in about 24 hours. Have fun, kiddies!
November 12th 2003, 12:48 AM
wizardb.gif
Kyle
Peasant He/Him Belgium
 
Niiiiiice. Can't WAIT to try it out!!
November 12th 2003, 04:42 AM
farmer.gif
very nice, but where is all the sprite crap we asked for?
November 12th 2003, 05:23 AM
custom_king.png
redink1
King He/Him United States bloop
A mother ducking wizard 
Isn't having a text-based DinkC++ file ending with the .c extension just asking for trouble and confusion when working with older DinkC files? Maybe .c2 or something?

'argument' is still very buggy. Don't rely on it, because all it does
it directly pops a value off the stack, and if other operations have
pushed values on, you'll be getting junk in your parameters.


While my knowledge in this area isn't too good, couldn't you use another pointer besides the stack and frame pointers to keep track of the arguments popped?

Also... is there an easy way to go straight from .c to .dpp? It seems like the creation of the DinkASM file is kinda worthless for most things, and for those few times where you need to edit or look at it, just deconvert it from the binary.

- Dictionaries (that is, arrays that use keys instead of indices :
&enemy_of["dink"] = &seth; etc)


Hmm... is this the same thing as a hash table?

Other than that... cripe, this looks incredible. Too bad TDP doesn't run on my computer at all
November 12th 2003, 09:00 AM
goblins.gif
Dukie
Peasant He/Him
 
Dang, my head hurts after reading that stuff! Better get Ted Shutes to write a new Dink C++ guide
November 12th 2003, 09:20 AM
wizardb.gif
Phoenix
Peasant He/Him Norway
Back from the ashes 
Why not separate integers from strings by doing something like &integername for integers and $stringname for strings or something? That would make it easier to separate which is which.
November 12th 2003, 10:02 AM
custom_king.png
redink1
King He/Him United States bloop
A mother ducking wizard 
I can't think of any programming language that does this... it just leads to other problems. What about floats? Doubles? The best solution is to just name your variables so its easy to tell what it is, or even do some hungarian notation like 'i_crap' for the name for a crap integer.
November 12th 2003, 11:05 AM
wizardg.gif
Paul
Peasant He/Him United States
 
BASIC used to work that way (only with the simbol on the end) but more recent implementations use the more common declaration method.
November 12th 2003, 05:54 PM
bonca.gif
Hi everyone, glad to see it's getting comments!

redink:

1. Yes, I am working on a better method for dealing with variable length parameter lists. 'argument' will probably vanish in the next release.
2. The next release will include a gcc-like compilation controller that you can use. I left .s files in there so that developers can debug their programs and flame me appropriately.
3. Yes, it is a hash table. Python calls it a dictionary.

Phoenix:
4. I considered doing something like that to start with, but left it behind because it would add unneccessary complexity to the parser. Besides, DinkC++ automatically converts integers to strings and back again as needed.

Misc:
5. Yes, floating point is on the way, along with a command-line DinkC++ parser.

Also:A
6. The compiler performs NO optimisation AT ALL. At the moment, there is no garbage collection either. I'm working on one.

Glad you all like it!
November 12th 2003, 06:15 PM
wizardb.gif
merlin
Peasant He/Him
 
very nice, but where is all the sprite crap we asked for?

Prioritization. I felt this was more important than any "sprite crap", so I moved it up on the list. If you request a feature, go to the SF.net site and put in a request for a feature addition. Too bad you don't ever go there to know that there *is* a feature request.

If you have problems with prioritization methods, then shut up. Or, you can IM me and THEN I'll tell you to shut up. No really, if it bothers you, let's talk. It'd be better than solving it Beuc's method.
November 12th 2003, 06:40 PM
custom_king.png
redink1
King He/Him United States bloop
A mother ducking wizard 
And don't forget the Merlin method of breaking someone else's code, blaming them for it, not recognizing that a mistake was made, and completely forget about an apology.
November 12th 2003, 07:32 PM
wizardb.gif
merlin
Peasant He/Him
 
1) I didn't break anyone's code
2) I only blamed the person responsible for what he did.
3) I seriously doubt it was a mistake
4) I didn't forget about an apology: I was waiting for one!

November 12th 2003, 07:58 PM
custom_king.png
redink1
King He/Him United States bloop
A mother ducking wizard 
I rest my case
November 12th 2003, 10:38 PM
wizardb.gif
merlin
Peasant He/Him
 
I see no case here.
November 13th 2003, 02:56 PM
bonca.gif
Settle down, settle down. Time to get to work on the garbage collector.