http://www.niksula.cs.hut.fi/project/ohtace/documents/te_tcl.html
CVS info: $Id: te_tcl.html,v 1.6 1996/11/25 13:02:35 tsalste Exp $
Tcl- ja C++ -ohjelmat voivat viestiä toisilleen kahteen suuntaan: C++ -ohjelmaa voi käyttää Tcl:stä käsin, ja Tcl-ohjelmaa voi puolestaan käyttää C++:sta käsin. Lisäksi Tcl-koodi voidaan kääntää yhtaikaa C++ -koodin kanssa siten, että molemmat sisältyvät samaan binääritiedostoon.
Ohjelmissa on luotu erityisiä luokkia Tcl-koodin kutsumiseen C++ -koodista käsin. Lisäksi niissä on välineitä myös C++ -funktioiden esittelyyn, jotta niitä voitaisiin kutsua Tcl-ohjelmasta.
Tcl.h
- Luokkien esittely
Tcl.cc
- Luokkien toteutus
Tcl2.cc
- Kaksi Tcl
-luokan metodia omassa tiedostossaan (evalf
ja resultf
) DEC OSF:n C++ -kääntäjän optimointivirheen takia
tcl2c++.c
- Lyhyt ohjelma, joka kääntää Tcl-ohjelmatiedostoja C++ -määrittelyiksi
.cc
- että .h
-tiedostoissa. Tästä seuraa lähinnä työmäärän kasvua koodin selvittelyssä sekä lisääntyneitä virhemahdollisuuksia, kun ei tarkalleen tiedetä, mitä koodin tekijänsä mukaan pitäisi tehdä. Virheiden vähentämiseksi koodiin onkin tutustuttava erityisen huolellisesti.
Luokka | Äitiluokka | Tarkoitus | Tiedostot |
---|---|---|---|
Tcl |
Tcl-koodin suoritus C++ -ohjelmasta käsin ja päinvastoin | Tcl.h, Tcl.cc, Tcl2.cc |
|
TclObject |
C++ -olioiden käsittely Tcl-ohjelmasta | Tcl.h, Tcl.cc |
|
CreateCommand |
TclObject |
C++/Tcl-olion luonti Tcl-koodista käsin käskyllä new |
Tcl.cc |
DeleteCommand |
TclObject |
CreateCommand in avulla luodun olion tuhoaminen käskyllä delete |
Tcl.cc |
Matcher |
CreateCommand in apuluokka |
Tcl.h, Tcl.cc |
|
EmbeddedTcl |
Tcl-tiedostojen upotus C++ -ohjelmaan | Tcl.h, Tcl.cc |
Tcl
Tcl
luokka on perusluokka, jota käytetään C++ - Tcl -linkin tekoon.
Tcl
alustetaan luokkametodilla init
, joka käynnistää yhden Tcl-tulkin. Kun Tcl
:stä luodaan instansseja, ne käyttävät tätä samaa Tcl-tulkkia.
Metodi | Toiminta | Paluuarvo |
---|---|---|
static void init(const char* application) |
Käynnistää Tcl-tulkin ja asettaa ohjelman nimen. | |
void eval(char *s) |
Suorittaa muuttujassa s olevan Tcl-koodin |
Tcl-koodin palauttama merkkijono on saatavissa funktiolla result . Virhetilanteessa suorittaa Tk-käskyn tkerror "virheilmoitus" |
void evalc(const char *s) |
Kuten eval , mutta säilyttää koodin koskemattomana |
|
void eval() |
Kuten eval , mutta suorittaa seuraavan käskyn buffer ista. evalf käyttää tätä. |
|
char* result() |
Viimeksi suoritetun Tcl-funktion paluumerkkijonon haku | Palauttaa osoittimen merkkijonoon |
void evalf(const char *fmt, ...) |
Kuten eval , mutta syntaksi kuten printf :ssä. Käyttö ilmeisesti näin:evalf("%s %s", kasky, param) |
Paluuarvo luetaan metodilla resultf |
void resultf(const char *fmt, ...) |
Metodin evalf paluuarvon luku, käyttö vähän hämärä |
Paluuarvo buffer issa |
void EvalFile(const char *file) |
Tcl-ohjelmatiedoston suoritus | Virhetilanteessa kirjoittaa virheilmoituksen stderr iin ja lopettaa koko ohjelman, muutoin ei palauta mitään |
char* var(const char* varname, int flags = TCL_GLOBAL_ONLY) |
Tcl-muuttujan arvon hakeminen | Osoitin muuttujan arvoon (merkkijono) | Seuraavia metodeja käytetään, kun halutaan kutsua C++ -funktiota Tcl:stä |
void CreateCommand(Tcl_CmdProc* cproc, ClientData cd=0, Tcl_CdmDeleteProc* dproc=0) |
C++ -funktion esittely Tcl-ohjelmassa käytettäväksi | |
void result(const char* p) |
Asettaa C++ -funktion paluumerkkijonoksi merkkijonon p |
TclObject
TclObject
in avulla C++ -olioita voidaan linkittää Tcl:ään siten,
että Tcl:stä voidaan kutsua C++ -olion metodeja. Tcl-koodin tasolla tämä tapahtuu jotakuinkin näin: olio komento parametrit
. Tämä kutsu välitetään C++ -olion metodille command
,
jolle annetaan parametreina komento
ja parametrit
merkkijonomuodossa.
TclObject
on virtuaalinen kantaluokka, josta johdetaan muota luokkia.
vicissä TclObject
ista on johdettu seuraavat luokat:
ColorHist, ColorModel, Crypt, InputDevice, OutputDevice, Grabber, Module, Network, PacketHandler, Source, SourceManager, Transmitter
ja BareWindow
. Näistä on johdettu edelleen aliluokkia.
TclObject
ylläpitää luokan sisäistä listaa kaikista määritellyistä olioista.
TclObject
in käyttöTclObject
ista siis johdetaan aliluokkia, joissa toteutetaan itse komennot.
Aliluokista synnytetään yleensä vain yksi instanssi, vaikka mitään rajoitusta määrälle ei ole.
Käytön kulku: Luodaan olio ja annetaan sille nimi konstruktorilla
TclObject::TclObject(name)
. name
voi olla myös NULL
,
jolloin nimi tulee automaattisesti muotoon _o4321
.
Kun kaikki oliot on luotu, kutsutaan luokkametodia TclObject::define()
, joka luo ilmoittaa Tcl-tulkille uudet komennot. Tcl-komennon nimeksi tulee yllä mainittu name
, joka on siis oliota vastaava Tcl-komennon nimi. Tcl-komento on muotoa name command param
, jota C++:n syntaksissa vastaisi jotakuinkin name.command(param)
.
Tcl-komentojen toteuttamiseksi aliluokkaan määritellään command(argc, argv)
-metodi,
jolla Tcl:stä tulevat parametrit tulkitaan ja toteutetaan. Metodin parametreina tulee C:n käytännön mukaisesti argc
, joka kertoo argv
:n koon. argv
on merkkijonotaulu, jonka sisältö on seuraava:
argv[0] |
Olion nimi (tarvitaan vain virheilmoituksia näytettäessä) |
argv[1] |
Komennon nimi |
argv[2]... |
Parametrit |
Metodi | Toiminta | Paluuarvo |
---|---|---|
static void define() |
Käy läpi kaikki tähän mennessä luodut TclObject -luokan (aliluokan) oliot ja luo niitä vastaavan Tcl-komennon Tcl-tulkkiin. define ä voidaan kutsua haluttaessa kuinka monta kertaa tahansa Tcl-komentojen päivittämiseen, jolloin uudet määrittelyt korvaavat vanhat. |
|
void class_name(const char* s) |
Asettaa oliolle luokkanimen | |
static TclObject* lookup(const char* name) |
Hakee luokansisäisestä listasta olion nimen mukaan | Osoitin löydettyyn olioon kai NULL |
static int callback(...) |
Kun Tcl kutsuu määriteltyä uutta funktiota, kutsu ohjautuu ensimmäisenä tähän luokkafunktioon.
callback ei tee muuta kuin kutsuu funktiota vastaavaa aliluokan command ia. |
TCL_OK, TCL_ERROR |
virtual int command(int argc, const char*const* argv) |
Tänne ohjautuvat kaikki Tcl:stä tulevat kutsut. Tämä on virtuaalifunktio, jonka jokainen aliluokka saa toteuttaa omalla tavallaan. Kantaluokan TclObject::command ia kutsutaan vain silloin, jos aliluokan command on saanut virheellisiä parametrejä. Tällöin TclObject::command näyttää sopivan virheilmoituksen.
|
TCL_ERROR |
CreateCommand
CreateCommand
-luokka luo Tcl-tulkkiin uuden käskyn new
. New-käskyllä voidaan Tcl-koodista käsin luoda uusia olioita yhtä aikaa sekä C++ -ohjelmaan että Tcl-ohjelmaan. Systeemin toiminta on hyvin monivaiheinen, ja se seljinnee parhaiten esimerkin avulla.
Esimerkki:
set transcoder [new transcoder jpeg/dct]
Tämä kaunis Tcl-koodinpätkä luo uuden JpegTranscoder
-luokan olion C++ -ohjelmaan. Samalla Tcl-ohjelmaan syntyy transcoder
-niminen olio, jonka metodeja kutsumalla Tcl-ohjelma voi ohjata JpegTranscoder
-luokan oliota C++ -ohjelmassa.
Tekninen toiminta
JpegTranscoder
-luokka on johdettuTclObject
-luokasta. Ollakseen tarpeeksi monimutkaista, sille on johdettu kaveriksi luokkaJpegTranscoderMatcher
kantaluokastaMatcher
, jolleJpegTranscoderMatcher::classname = "transcoder"
.Kun Tcl-ohjelma käskee
new transcoder jpeg/dct
, välittyy kutsu ensinCreateCommand.command
iin, joka puolestaan kutsuuMatcher::lookup("transcoder", "jpeg/dct")
. Tämä metodi etsii käsiinsäJpegTranscoderMatcher
-luokan ainoan instanssin nimeltätranscoder_matcher_jpeg
, ja komentaa tälletranscoder_matcher_jpeg.match("jpeg/dct")
.Nyt alkaa loppu jo häämöttää.
transcoder_matcher_jpeg.match
luo uudenJpegTranscoder
-olion, ja loppujen lopuksi tulos on, että Tcl:ssä muuttujatranscoder
viittaa tähän olioon.
DeleteCommand
CreateCommand
in vastaluokka.
Se luo Tcl-kieleen uuden käskyn, joka tuhoaa new
-komennon avulla luodun olion.
Esimerkki:
delete transcoder
EmbeddedTcl
EmbeddedTcl
on luokka, jolla .tcl
-tiedostot voidaan sisällyttää C++ -ohjelmaan.
Systeemi toimii siten, että Tcl-koodia luodaan tavanomaisiin .tcl
-tiedostoihin.
Ohjelman käännösvaiheessa käytetään hyväksi tcl2c++
-ohjelmaa, joka lukee Tcl-koodin ja muokkaa sen C++ -merkkijonoksi .cc
-tiedostoon. Tämä tiedosto sitten käännetään muun C++ -ohjelman mukana.
Syntyvä C++ -tiedosto luo EmbeddedTcl
-olion,
jonka tehtävä on säilyttää koodi. Kaikkien olioiden koodi suoritetaan ohjelman
käynnistyksen yhteydessä luokkakutsulla EmbeddedTcl::init()
.
Metodi | Toiminta | Paluuarvo |
---|---|---|
static void init() |
Kutsuu ensin TclObject::define a, joka Käy läpi kaikki tähän mennessä luodut TclObject -oliot ja luo niitä vastaavan Tcl-komennon Tcl-tulkkiin. Tämän jälkeen suorittaa kaikkien EmbeddedTcl -olioiden sisältämän koodin. |
|
EmbeddedTcl(int pass, const char* code) |
Konstruktori. Pass on kokonaisluku 0, 1, 2, ... joka määrää sen järjestyksen, jossa EmbeddedTcl-oliot suoritetaan (ne joiden pass =0, suoritetaan ensin jne.).
|
TclObject
in kohdalla selitettiin yksi tapa kutsua C++:aa Tcl:stä käsin oliorajapinnan avulla.
Seuraavassa puolestaan esitellään keino, jolla voidaan kutsua ihan "tavallisia" funktioita ilman TclObject
ista periytyvää luokkaa.
C++ -funktio täytyy esitellä Tcl:lle edellämainitulla komennolla Tcl::CreateCommand(Tcl_CmdProc* cproc, ClientData cd=0, Tcl_CdmDeleteProc* dproc=0)
. Lisäksi C++ -funktion on noudatettava tiettyä rajapintaa.
Tcl_CmdProc
mukaan seuraavasti:
typedef int Tcl_CmdProc(ClientData clientData,
Tcl_Interp *interp,
int argc,
char *argv[]);
Kaksi ensimmäistä parametria ovat Tcl:n käyttöä varten. clientData
osoittaa Tcl::buffer_:
iin ja interp Tcl::tcl_
:ään. Merkityksellisiä parametreja ovat argc
ja argv
, jotka sisältävät perinteiset C++ -funktion parametrit, ja joita C++ -funktio siis käyttää hyväkseen.
int
-tyyppisistä paluuarvoista: TCL_OK, TCL_ERROR, TCL_RETURN, TCL_BREAK, TCL_CONTINUE
. Nämä määrittelevät, onnistuiko C++ -funktion suoritus.
Funktion Tcl-ohjelmalle palauttaman paluuarvon on oltava merkkijono (koska Tcl käsittelee vain merkkijonoja). Mikäli funktion arvona palautetaan TCL_OK
, palautettava merkkijono käsitellään Tcl-ohjelmassa C++ -funktion paluuarvona. Mikäli puolestaan palautettiin TCL_ERROR
, merkkijono käsitetään virheilmoitukseksi (joka näytetään käyttäjälle).
Palautettava merkkijono asetetaan metodilla Tcl::result("paluuarvo").
Mikäli ei haluta käyttää mainittua Tcl-luokan metodia, voi arvon toki asettaa suoraan:Palautettava merkkijono asetetaan kutsulla
Tcl_SetResult(interp, "paluuarvo", TCL_VOLATILE)
, jolloin Tcl huolehtii merkkijonon kopioimisesta sopivalle muistialueelle ja sen tuhoamisesta muistista. Palautettavaa merkkijonoa voi myös rakentaa komennollaTcl_AppendResult(interp, "paluu", "arvo", ... , NULL)
jokoTcl_SetResult
in jälkeen tai myös sitä käyttämättä.Seuraavat komennot ovat myös käytettävissä paluumerkkijonon käsittelyyn (eivät keskeisiä):
Tcl_AppendElement(interp, string)
KutenTcl_AppendResult
, mutta käytetään Tcl:n listojen rakentamiseenTcl_ResetResult(interp)
Käytetään paluumerkkijonon tyhjentämiseenTcl_FreeResult(interp)
Käytetään paluumerkkijonon tyhjentämiseen, jos paluumerkkijono halutaankin vaihtaa toiseen