Lore And Lutes Object Oriented Programming Language Documentation For C++ Game Developers Vs. 1.01 (10/27/2002)
Written By: Andy Stone
ASFC By: Andy Stone (astone42@attbi.com)
Visit: http://loreandlutes.sourceforge.net for more information.
See copying.txt or copying for licensing information.
sound better.
Example compilation:
g++ *.cpp -lasfc -lloop -lSDL -lSDL_image
#include <loop/loop.h>
#include <loop/looplib_standard.h>
int main(int argc, char *argv[])
{
LOOP_LOOP LOOP;
LOOP_LOOPLib_Standard lib;
string file;
string class;
string member;
cout << "Linking the standard library to LOOP\n"; lib.Link(&LOOP);
cout << "What file would you like to execute? "
cin >> file;
cout << "\nLoading: " << file << endl
LOOP.ReadClass(file);
cout << "What class would you like to create an instance of?";
cin >> class;
cout << "\nCreating a new instance of class"
oLOOP.NewInstance(0, class, SCOPE_LOCAL);
cout << "What member would you like to call: ";
cin >> member;
oLOOP.GosubInstance(class, member);
cout << "\nGosubing " << member << endl;
cout << "Executing file for 100 iterations:\n"
for(int i = 0; i < 100; i++)
oLOOP.RunInstance(0);
cout << "Finished\n";
return 0;
}
Go ahead and create a project, copy and paste that code, and compile. If everything works as it should then you can use this program to test LOOP scripts that show up in this document.
@test
:test
#cout "Hello, World!"
#return
^
Next run the generic LOOP Scriipt runner and enter the following information:
Linking the standard library to LOOP
What file would you like to execute? test.script
Loading: test.script
What class would you like to create an instance of? test
Creating a new instance of class
What member would you like to call: test
Gosubing test
Executing file for 100 iterations:
If everything works properley you should get these results:
Hello, World!
:SayHello
#cout "Hello, World!"
#Return
^
@TestClass
Class names can contain any character you want except [, ], (, or ).
To end a class place a caret at where the class ends. For example a generic class format is:
@ClassName
//Class Code
^
Anything after the carret will be ignored by the LOOP parser so you can place comments and notes there if you'd like. Be careful to end the class though as forgetting to do so can confuse LOOP and might freeze it.
#cout "This command couts"
There are three types of parameters LOOP accepts, ints, floats, and strings. Constants of those three types are passed just like that are in most languages. For example a string is passed by enclosing the string in double quotes ("), ints are passed by typing a whole number, and floats are passed by typing a number with a decimal point. Ints and floats may be positive or negative.
Example:
#cout "String "
#coutInt -1234
#cout " "
#coutFloat 1.234
Result:
String -1234 1.234
Variables are passed by enclosing the variable identifier in brackets [].
string Holds a string of characters like "Hello"
int Holds an integer number like 123. Int is held in memory just like an int in C++. float Holds a number with a decimal point, like 123.4. In memory a float is actually stored as a double.
There are also two categories of variables public and private. By default whether a variable is public or private won't effect LOOP. You have to program in the difference yourself if you like.
To create a public variable write a percent sign (%) followed by the type of variable, a space, and in double quotes the identifier you want for this variable. Example:
%string "varString" //Creates a string called varString %int "varInt" //Creates an int called varInt %float "varFloat" //Creates a float called varFloat
To create a private variable write a dollar sign ($) followed by the type of variable, a space, and in double quotes the identifier you want for this variable. Example:
%string "varPubString" //Creates a public string called varPubString %int "varPubInt" //Creates a public int called varPubInt %float "varPubFloat" //Creates a public float called varPubFloat
To pass a variable to a command simply enclose the variable's identifier in []s. For example:
%string "message"
#StrEqu [message] "Hello, World!"
#cout [message]
:label
Label's are used to mark the beginning of methods (sub routines), that #Gosub or #Goto commands call.
The rightmost column in the table below specifies what types parameters are passed. I for int, F for float, S for string. If a parameter is enclosed in []s that means a variable has to be passed. For example the table entry for RemoveSubStr looks like this:
RemoveSubStr Removes the sub string between the two passed ints. [S]II
So RemoveSubStr expects a string variable to be passed and two integer variables or constants.
Example:
@Test
%string "string"
:Test
#StrEqu [string] "String oops!"
#RemoveSubStr [string] 7 11
#cout [string]
#Return
^
Result:
String!
Cout Writes a string onto the console S CoutFloat Writes a float onto the console F CoutInt Writes an int onto thte console I
CoutDebugInfo Display LOOP debugging information.
IfStrEqu If two strings equal execute the command on the SS next line. If the next command is #begin execute all commands between #begin and #end. If the two strings aren't equal skip the next line unless it's a begin and which case skip to the #end command associated with the #begin command. IfIntEqu Like IfStrEqu but compares two ints II IfIntGT If int is greater than II IfIntLT If int is less than II IfIntGTI If int is greater than or equal to II IfIntLTI If int is less than or equal to II IfFloatEqu If float is equal to FF IfFloatGT If float is greater than FF IfFloatLT If float is less than FF IfFloatGTI If int is greater than or equal to FF IfFloatLTI If int is less than or equal to FF
Begin Used to mark the beginning of a conditional block for #If commands End Used to mark the ending of a conditional block for #If commands
StrEqu Sets the the first string passed equal to the [S]S second AppendStr Add the 2nd string passed to the end of the 1st [S]S InsertStr Insert 2nd string into 1st [S]SI RemoveSubStr Removes the sub string between the two passed ints [S]II UpperString Capitalize the 2nd string, place it in the 1st [S]S SubStr Grab the sub string between the 2 int locals [S]SII StrSize Return the size of a string [I]S
IntEqu Set int equal to [I]I IntInc Increment the value of an int by 1 [I] IntDec De-increment the value of an int by 1 [I] IntAdd Find the sum of two ints [I]II IntSub Find the difference between two ints [I]II IntMul Find the product between two ints [I]II IntDiv Return the ratio between two ints [I]II IntMod Find the modulo between two ints [I]II
FloatEqu Set float equal to [F]F FloatInc Increment the value of a float by 1 [F] FloatDec De-increment the value of a float by 1 [F] FloatAdd Find the sum between two floats [F]FF FloatSub Find the difference between two floats [F]FF FloatMul Find the product between two floats [F]FF FloatDiv Find the ratio between two floats [F]FF
Goto Set the point of execution to a label S GoSub Set the point of execution to a label. Return to S this point when the next #Return command is called. Send Perform a goto command on another instance SS GoSend Perform a gosub command on another instance SS Return Used for marking the end of a method called by a #GoSub or #GoSend statement
@Mathematician
%int "counter"
%ing "mod"
:PrintEvens
#IntEqu [counter] 0
:Update
#IfIntLTI [counter] 100 #Begin #coutInt [counter] #cout " " #IntAdd [counter] [counter] 2 #Goto "Update" #End
#Return
^
To run this script using the generic LOOP runner enter the following info:
Linking the standard library to LOOP
What file would you like to execute? script.script
Loading: script.script
What class would you like to create an instance of? Mathematician
Creating a new instance of Mathematician
What member would you like to call: PrintEvens
Gosubing PrintEvens
Executing file for 100 iterations:
The way LOOP handles commands is fairly easy, you create a function that maps to your command, then you tell LOOP where this function is, what command it links to, and what parameters are passed to the command. Whenever LOOP encounters your new command in a script it calls through a function pointer your function. This sounds easy but its not!
Anyways, the first thing you need to do is create .h and .cpp files for your library. Copy in the code for each file as seen in appendix A (near the bottom of the file).
You'll notice that the .h file includes the following headers:
#include <loop/loopmacros.h>
#include <loop/info.h>
#include <loop/loop.h>
loopmacros includes macros that make it possible for you to pass a function within a class to LOOP, if you've ever used function pointers you may have encountered troubles with this before. The macro will create a static member in your library class that will map to the dynamic member to be executed. If you don't understand that don't worry just know you have to use the macros in there.
The info header includes an info object, an info object will be passed to the function you create for your new command. The info object holds information about what parameters are passed, what instance is passing it, and includes a few helpful members that make LOOP command programming easier for you.
And the loop header includes the main LOOP object which will get passed to a member your about to program called Link(). Link() will link() all of the commands in your library to the main LOOP_LOOP object.
Now go through the file and anywhere it says Insert<something>here insert the appropriate name. For example replace:
InsertNameHere: With the name of your library. For example MyLib. InsertCommandType: With a helpful description about what types of commands
you're defining below. InsertCommmandName: Insert the name of the command you want to create.
Pay close attention to this line:
LOOPPORT(LOOPCMDPRT_InsertCommmandName, LOOPLib_InsertNameHere, LOOPCMD_InsertCommandName);
LOOPPORT is the macro that defines members for your LOOP command that will be called whenever the command is encountered in a script. The first parameter passed will define a port function which helps resolve some issues with how function pointers work, the second param passed is the name of the class your member functions dwell under, and the third parameter tells the macro what you want your actual member function to be called.
If you want your library to include more than one command simply copy that line as many times as necessary replacing all the InsertNameHeres with the name of each command.
Next near the bottom of the .cpp file you should have these lines:
void LOOPLib_InsertNameHere::LOOPCMD_InsertCommandName(LOOP_Info oInfo)
{
//Inset command code here
}
This is a template of what your member function will look like. Replace the Insert<something> text with the appropriate information. If you like you can change the identifier of the LOOP_Info variable (oInfo) passed.
Next scroll up to your Link() member, which will link your library to the LOOP object. Take a gander at this code:
poLOOP->NewCommand("InsertCommandName", &LOOPCMDPRT_InsertCommandName, this);
poLOOP->AddParam(PARAM_INSERTPARAMTYPE1); poLOOP->AddParam(PARAM_INSERTPARAMTYPE2); poLOOP->AddParam(PARAM_INSERTPARAMTYPE3); poLOOP->AddParam(PARAM_INSERTPARAMTYPE4);
Replace all Insert<somethings> with the correct information. The AddParameter calls below tell LOOP what type of parameters will get passed to your new command in the order they should get passed. Possible params to pass include:
PARAM_INT Pass an int variable or int constant PARAM_FLOAT Pass a float variable or float constant PARAM_STRING Pass a string varaible or string constant PARAM_INT_REF Pass an int variable PARAM_FLOAT_REF Pass a float variable
PARAM_STRING_REF Pass a string variable
You can add as many or as a few parameters as you'd like. If your library has more than one command (most likely) simply copy and paste the code for all the commands you need. For example a library for two commands called #WriteInt and #WriteString might have a Link() member that looks like this:
void LOOPLib_TestLib::Link(LOOP_LOOP* poLOOP) {
poLOOP->NewCommand("WriteInt", &LOOPCMDPRT_WriteInt, this); poLOOP->AddParam(PARAM_INT); poLOOP->NewCommand("WriteString", &LOOPCMDPRT_WriteString, this); poLOOP->AddParam(PARAM_STRING);
}
int GrabInt (int iNumber); double GrabFloat (int iNumber);
string GrabString (int iNumber);
int GrabIntRef (int iNumber);
int GrabFloatRef (int iNumber);
int GrabStringRef (int iNumber);
Set the iNumber param equal to which <int/float/string> is passed. For example if you had a command called drawline that took 4 ints for coods it might look like this:
void LOOPLib_MyLib::LOOPCMD_DrawLine(LOOP_Info oInfo) {
FunctionElsewhereThatDrawsALine ( oInfo.GrabInt(0), oInfo.GrabInt(1), oInfo.GrabInt(2), oInfo.GrabInt(4) );
}
Realize that if you have a member that gets passed variables both by reference and by non-reference the iNumber parameter for non reference grabbing members also maps to the reference passed variables. For example if you had a command called PassVars that took i[i]i and you executed this in a script:
#PassVars 10 20 30
Then:
oInfo.GrabInt(0) = 10
oInfo.GrabInt(1) = 20
oInfo.GrabInt(2) = 30
oInfo.GrabIntRef(0) = An integer representing the location of the intref
variable. This will be iLocation for the SetInt() member if you choose to use it.
If you'd like to change the value of a variable passed by reference you can use the Variable Setting members of the LOOP_Info object:
void SetInt (int iLocation, int iTo); void SetFloat (int iLocation, double dTo); void SetString(int iLocation, string sTo);
Errors, Bugs, Questions, Comments?
#include <loop/loopmacros.h>
#include <loop/info.h>
#include <loop/loop.h>
class LOOPLib_InsertNameHere
{ public: //- [Constuctors] - LOOP_LOOPLib_Standard(); void Link(LOOP_LOOP* poLOOP); //- [InsertCommandType] - LOOPPORT(LOOPCMDPRT_InsertCommmandName, LOOPLib_InsertNameHere, LOOPCMD_InsertCommandName); private: //Vars
};
LOOPLib_InsertNameHere::LOOPLib_InsertNameHere()
{
}
void LOOPLib_InsertNameHere::Link(LOOP_LOOP* poLOOP) {
poLOOP->NewCommand("InsertCommandName", &LOOPCMDPRT_InsertCommandName, this); poLOOP->AddParam(PARAM_INSERTPARAMTYPE1); poLOOP->AddParam(PARAM_INSERTPARAMTYPE2); poLOOP->AddParam(PARAM_INSERTPARAMTYPE3); poLOOP->AddParam(PARAM_INSERTPARAMTYPE4); //Repeat for more commands...
}
void LOOPLib_InsertNameHere::LOOPCMD_InsertCommandName(LOOP_Info oInfo)
{
//Inset command code here
}