Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C++: Skriptituki

Gaxx [17.07.2007 14:42:00]

#

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
}

matpit [10.08.2007 23:03:34]

#

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.".

Meitzi [11.08.2007 02:26:51]

#

Aika hyvältä näyttää. Tämä ei taida olla enää ohjelmoinnin alkeet kurssilta.

temu92 [15.08.2007 21:47:04]

#

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

Turatzuro [20.08.2007 15:50:34]

#

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

Gaxx [20.08.2007 21:17:31]

#

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 :)

fergusq [22.08.2013 17:42:36]

#

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!");

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta