Viikko vierähti ja valmista tuli. Seuraavaksi esittelen G-Scriptin, olkaa hyvä. Se on yksi luokka, joka lisää ohjelmaan scriptituen.
Pääperiaatteittain koodi toimii siten, että scriptikoodi parsitaan Parse()-funktiolla ja aliparsereilla sanoiksi(Word), jonka jälkeen suoritetaan sanat. Koodiin kannattaa lähteä tutustumaan "script.h":n kautta, sillä siellä se on nidottu loogiseksi kokonaisuudeksi. Jos ei halua tutustua koodiin, vaan ottaa sen suoraan käyttöön, kannattaa tutustua manual.txt:n sisältöön(löytyy alempaa ladattavasta paketista). Siellä on kerrottu tarkemmat tiedot ja ominaisuudet G-Scriptistä.
Koko paketin voi ladata tästä.
Ja kyllä, koodia saa käyttää vapaasti suoraan tai muokattuna omassa ohjelmassa, eikä tarvitse mainita alkuperäistä tekijää. Tietty olis kiva tietää, jos tätä käytetään jossain projektissa.
Nykyään sivulla näkyy vain script.h ja example.cpp. Script.cpp löytyy edelleen ladattavasta paketista(kts. yllä). Tämä koodin suuresta koosta johtuen.
Uusin versio 1.3
16.12.2009 — Päivitin vinkin, koska skriptitulkkiin oli tullut korjauksia ja parannuksia. Käytän tulkkia itse eräässä pitkään tekeillä olleessa roolipeliprojektissani ja siinä se on toiminut moitteitta.
script.h
// G-Script versio 1.3 // #include <string> #include <vector> #ifndef script_h #define script_h using namespace std; // Muuttujatyypit const int VOID = -1; // Ei mikään const int INT = 0; // Kokonaisluku const int FLOAT = 1; // Liukuluku const int STRING = 2; // Teksti // Palautusarvot const int ILLEGAL_PLACEMENT = -4; // Laiton sijoitus const int UNDEFINED_OPERATOR = -3; // Tunnistamaton operaattori const int DIVIDED_BY_ZERO = -2; // Jaettiin nollalla const int FAILED = -1; // Epäonnistui const int SUCCESS = 0; // Onnistui struct Var { string name; // Nimi int type; // Tyyppi int members; // alkioiden määri void *address; // osoite }; struct Func { string name; // Nimi void* (*address)(vector<void*> param); // Osoite int type; // Palautusarvon tyyppi }; struct Word { int wtype; // Sanan tyyppi int vtype; // Arvon tai operaatorin tyyppi void *value; // Arvon osoitin string name; // Nimi }; struct Segment { bool run; // Suoritetaanko lohko int type; // Tyyppi vector<Word> condition; // Ehto int wstart; // silmukan alku }; class Script { vector<Var> var; // Muuttujat vector<Func> func; // Funktiot vector<Segment> segment; // Lohkopino // Parserit int Parse(string sentence, int cstart); // Parsii lauseen int ExeWords(vector<Word>& word); // Suorittaa sanat // Laskuoperaatiot Word CalculateClause(vector<Word>& word, int start, int len); // Laskee lausekkeen Word CalculateTwoValue(Word a, Word oper, Word b); // Laskee kaksi lukua // Aliparserit Word Define(string word, int start, int len); // Muuttujamäärittely Word Value(string word, int start, int len); // Arvo Word String(string owrd, int start, int len); // Teksti Word Variable(string word, int start, int len); // Muuttuja Word Function(string word, int start, int len); // Funktio Word Operator(string word, int *start); // Mikä operaattori int Segments(string word, int start, int len); // If/while string Script::trim(string& text, int start, int length = -1); // Välilyöntien poisto // Muistin vapauttajat void FreeWords(vector<Word>& word); // Vapauttaa sanojen sisäisen muistin void FreeWord(Word& word); // Vapauttaa sanan sisäisen muistin void FreeString(void*& pointer); // Vapauttaa string-muuttujan public: Script(); // Constructori ~Script(); // Destructori int RegVar(string name, int type, int members, void *address); // Registeröi muuttujan int RegFunc(string name, int type, void* (*address)(vector<void*> param)); // Registeröi funktion int Execute(string script, int *error); // Suorittaa scriptin }; #endif
example.cpp
#include <iostream> #include "script.h" void* Print(vector<void*> param); int main() { Script script; string command; int *err; // Scriptistä käsiteltävät muuttujat string name; int age; // Registeröidään muuttujat script.RegVar("name", STRING, 1, &name); script.RegVar("age", INT, 1, &age); // Registeröidään funktio script.RegFunc("Print", STRING, Print); // Määritetään suoritettava scripti command = "name = \"Matti\"; age = 15; Print(\"Terve \" + name + \", \" + age + \"v!\");"; // Suoritetaan scripti if(script.Execute(command, err) > 0) std::cout << "ERROR: " << *err << std::endl; else std::cout << "SUCCESS" << std::endl; // Korvaa jollain, jos kiinnostaa system("pause"); return 0; } // Tulostus funktio void* Print(vector<void*> param) { std::string *str = (std::string*)param.at(0); // Luodaan osoitin ensimmäiseen parametriin std::cout << str->c_str() << std::endl; // Tulostetaan parametrin arvo }
Näyttää todella hyvältä, varmasti on minulle ainakin tulevaisuudessa käyttöä. Valitettavasti olen vielä sen verran aloitteleva C++ kanssa että en osaa koodin kannalta minkäänlaista komenttia oikein antaa, muuta kuin että siististi on kirjoitettu ja hyvältä näyttää. :}
EDIT: Millähän kääntäjällä tämä on kääntynyt oikein? Oma mingw32 herjaa "This application has requested the Runtime to terminate it in an unusual way. Please contact the apllication's support team for more information.".
Aika hyvältä näyttää. Tämä ei taida olla enää ohjelmoinnin alkeet kurssilta.
Kirjotusvirheitähän löytyy (tosin varmaan pienin ongelmista)
DIVINED_BY_ZERO --> Jumaloitu zerolla manual.txt:ssä on registeröityä
Makeelta toi kyl näyttää :D Melkeempä Luakin jää tälle kakkoseksi :D
temu92 kirjoitti:
DIVINED_BY_ZERO --> Jumaloitu zerolla
Eikös se olisi pikemminkin "ennustettu nollalla" tai vastaavaa?
Koodipätkä näyttää siistiltä, täytyy pitää mielessä jos/kun sattuu itse tarvimaan. Aina plussaa kun ei tarvitse alkaa itse väsäämään :P
matpit kirjoitti:
EDIT: Millähän kääntäjällä tämä on kääntynyt oikein? Oma mingw32 herjaa "This application has requested the Runtime to terminate it in an unusual way. Please contact the apllication's support team for more information.".
www.bloodshed.net kirjoitti:
Dev-C++ version 4.9.9.2, includes full Mingw compiler system with GCC 3.4.2 and GDB 5.2.1
Tollasella paketilla ei tuu mitään herjauksia. Lisäksi olen testaillu koodia aika lailla, enkä ole havainnut siinä virheitä pitkään aikaan. Virheet ovat löytyneet skriptin puolelta.
Edit: DIVINED -> DIVIDED :)
Parseri on toteutettu huonosti.
name = "Matti"; age = 15; Print("Terve " + name + "; " + age + "v!");
Kun suoritan koodin samalla tavalla kuin esimerkissä, ohjelma tulostaa:
Terve Matti Muistialueen ylitys
Tämä johtuu siitä, että tulkki ajattelee, että merkkijonon sisällä oleva puolipiste päättää lauseen. Mitään virhettä ei myöskään synny siitä, että funktiokutsulta puuttuu toinen sulku.
Tulkki käyttää lekseriä (joka on hämäävästi funktiossa Parse), mutta vain laskulausekkeisiin. Ehdot, silmukat, puolipisteet, yms parsitaan yksinkertaisesti etsimällä merkkejä ja vertaamalla merkkijonoja.
Myöskin seuraava koodi aiheuttaa virheen samasta syystä.
name = "Matti"; age = 15; Print("Terve " + name + "{ " + age + "v!");
Aihe on jo aika vanha, joten et voi enää vastata siihen.