Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Funktioparseri

Sivun loppuun

kayttaja-3842 [23.05.2007 15:45:55]

#

Juu elikkäs, mite tulisi tehdä oma funktio parseri? Eli parseri joka ottaisi talteen funktion argumenteille syötetyn datan. Eli jos käyttäjä antaa komennon char *komento = "tiedot('kansio','a')" niin parseri katsoo eka että mikä funktio on kyseesttä eli "tiedot" jos "tiedot" funktio löytyy niin katsotaan mitä dataa sen argumennteihin on laitettu. Jos taas "tiedot" funktiota ei löydy, niin tuloestetaan vaikka "Komentoa ei ole olemassa" tai jos funktio on mutta argumentit on väärin niin "Virheelinen argumentti".

Edit1: Nytten pitäisi saada tehtyä oma eli sscanf kokeilin, mutta se ei bugaa vähän tässä, eli oma pitäisi tehdä.

Mazzimo [23.05.2007 16:00:10]

#

Vai että ollaan omaa ohjelmointi-/skirptikieltä teossa. Valitettavasti asia ei ole aivan noin suorapiirteinen. Jaa rivi osiin (tokeneihin) jonka jälkeen ala tarkistamaan riviä osa kerrallaan. Näiden osien perusteella sitten tarkistat, onko rivi laillinen. Jos noin kunnianhimoista projektia alkaa tekemään, ei näin helppoja asioita pitäisi kysyä. Tämä kun on helpoimmasta päästä. ;)

kayttaja-3842 [23.05.2007 16:43:50]

#

En ole suoranaisesti omaa kieltä tekemässä. Pitäisi saada tehtyä pieni kielitulkki vain. Eli kyseessä on vain parista funktiosta. Itse yritin tehdä tuota flex:in avulla, mutta päädyin sitten "oma" ohjelmoimaan. Pitää vielä kai sitte yrittää koodata tuota parseria.

Antti Laaksonen [23.05.2007 17:09:56]

#

Ovatko komennot aina muotoa "nimi(a,b,c)", jossa "nimi" on komennon nimi ja "a", "b" ja "c" ovat parametreja (niitä voi tietysti olla eri määrä). Tällaisten komentojen tunnistukseen ei tarvita kovin monimutkaista järjestelmää.

Ensimmäinen vaihe voisi olla selvittää komennon nimi. Tämä onnistuu tutkimalla merkkejä alusta alkaen, kunnes tulee vastaan aloitussulku. Tätä ennen tuleva osuus on komennon nimi. Jos vielä viimeinen merkki on lopetussulku, komento on muuten kunnossa, mutta pitää vielä tutkia parametrit.

Myös parametrit saa selville käymällä merkkejä läpi yksi kerrallaan. Jos vastaan tulee pilkku tai lopetussulku, parametrit on käyty läpi. Hieman vaikeampi tilanne on, jos parametrien sisällä voi olla pilkkuja tai sulkuja. Tällöin täytyy pitää kirjaa heittomerkeistä (onko merkkijono kesken).

Tarvittava koodi voi olla aika pitkä, mutta se muodostuu yksinkertaisista osista. Eli jos mietit järkevästi, miten tuollaisen komennon pystyy tunnistamaan merkkejä tutkimalla, homman pitäisi onnistua.

kayttaja-3842 [23.05.2007 17:22:10]

#

joo o, mite saan char d[1] siirettyä esim char* a:lle? Eli jos d = "(g)" niin sitten g sijainti on merkki jonossa [1]. Eli eikös se saada niin et siiretään d[1] a:lle. Sitten a = "g", mutta tämä ei onnistu char* a = d[1]. Miten tämä tulisi tehdä oikein?

Antti Laaksonen [23.05.2007 17:29:51]

#

Jos muuttuja a on pelkkä yksi merkki, määrittele se "char a". Sitten aikanaan voit kirjoittaa "a = d[1]", jolloin merkkijonon d kohdassa 1 oleva merkki (eli merkkijonon toinen merkki) kopioituu muuttujaan a. Siis yksi char-muuttuja on yksi merkki, ja kun tällaisia on useampia peräkkäin, muodostuu merkkijono.

kayttaja-3842 [23.05.2007 17:45:54]

#

Vielä yksi juttu. Miten saan lisättyä char muuttujaan aina tekstiä? Itse koitin

  sprintf (tuloskomento,tuloskomento+"%s",vkomento[i]);

Antti Laaksonen [23.05.2007 18:35:32]

#

Funktiolla strcat voi lisätä merkkijonon toisen perään. Sama onnistuu myös funktiolla sprintf vähän pidemmin.

strcat(tuloskomento, vkomento);
sprintf(tuloskomento, "%s%s", tuloskomento, vkomento);

Muista huolehtia, että merkkijonoissa on tarpeeksi tilaa.

kayttaja-3842 [23.05.2007 19:30:48]

#

Nää charrit taitaa olla liitoutuneita jotenki muo vastaan, ei oikein tahdo toimia.

char *vkomento;
vkomento = "k(a)";
char tuloskomento[1000];
int i = 0;

while(i < strpituus(vkomento)){

if(vkomento[i] != "("){
sprintf(tuloskomento, "%s%s", tuloskomento, vkomento[i]);
}

i++;

}

cout << tuloskomento;

Metabolix [23.05.2007 19:38:55]

#

Antti, sprintf-funktion toiminta ei taida olla määritelty, jos sillä yrittää kirjoittaa tekstin itseensä. Pitäisi mieluummin etsiä tekstin loppukohta ja jatkaa siitä:

sprintf(&teksti[strlen(teksti)], "%s", jatkoteksti);

kayttaja-3842, suosittelen tutustumista osoittimiin, merkkijonoihin ja (s)printf-funktioon jonkin oppaan kanssa. %s tarkoittaa tekstiä (char*), yksi merkki olisi vain %c. (Ja mikä on tuo strpituus, eikö valmis funktio strlen sopisi?)

Antti Laaksonen [23.05.2007 20:09:59]

#

Heittomerkkien sisällä on merkki, lainausmerkkien sisällä on merkkijono. Eli 'a' ja "a" ovat kaksi eri asiaa. Merkkijonon lopussa on aina nollamerkki, jolloin "a" muodostuu merkeistä 'a' ja '\0'. Merkkejä voi vertailla C:n tavallisin keinoin (==, != jne.), mutta merkkijonoja täytyy vertailla merkki kerrallaan (esim. funktiolla strcmp). Ehkä helpointa on ajatella, että merkki on yksi muuttuja ja merkkijono on taulukko (niin kuin asia onkin).

Metabolix: Hyvä huomautus, ei kannata ottaa mallia edellisestä viestistäni. Tässä tapauksessa tuo tekeleeni ehkä toimii, jos hyvin käy, mutta jos kaksi viimeistä parametria vaikka vaihtaa toisinpäin, niin voi tapahtua kummia.

Mazzimo [23.05.2007 20:23:36]

#

Jos teet C:llä tälläisten merkkijonojen kanssa puljaaminen on ymmärrettävää, mutta jos teet C++:lla, en ymmärrä miksi pitää lyödä päätä kiveen. Siinä tapauksessa tutustu std::string-luokkaan. Niiden käsittely on paljon turvallisempaa, helpompaa ja aloittelijalle loogisempaa.. ;)

Mutta jos teet C:llä niin tämä posti on hyödytön.

kayttaja-3842 [23.05.2007 23:03:31]

#

Tein tälläseen nopeen testin, mutta ei oikein tahdo toimia toi ehto tuolla

if(tuloskomento == "print"){
 cout << "Loyty";
}else{
cout << "Ei loytynyt";
}

vaikka tuloskomento = "print"

#include <iostream>
#include <string.h>

using namespace std;


int strpituus(char * teksti)
{
int a,aika = 0;
while(teksti[a] != '\0')
{
a++;
aika++;
}
return aika;
}






char *  TULKKI_parseri(char* komento){

/* Paresri */
char *vkomento;
vkomento = komento;
char tuloskomento[1000];
char tulosargumentit[1000];
string scan;
string scan2;
int i = 0;
bool funktio_tunnistus = false;

while(i < strpituus(vkomento)){

scan = vkomento[i];

if(scan != "("){
sprintf(&tuloskomento[i], "%c",vkomento[i]);


}else{
funktio_tunnistus = true;
int a_ja = i+1;
int alku = 0;
i = strpituus(vkomento)+1;
while(a_ja < strpituus(vkomento)){

scan2 =  vkomento[a_ja];

if(scan2 != ")"){
 sprintf(&tulosargumentit[alku], "%c",vkomento[a_ja]);
}else{


a_ja = strpituus(vkomento)+1;
}
alku++;
a_ja++;
}


}

i++;

}

/* Parseri loppuu */

if(tuloskomento == "print"){
 cout << "Loyty";
}else{
cout << "Ei loytynyt";
}

}

Käyttö

#include <iostream>
#include <string.h>
#include "tulkki.h"

using namespace std;

int main(int argc,char *argv[]){
TULKKI_parseri("print(moi)");
system("PAUSE");
return 0;
    }

Megant [23.05.2007 23:20:48]

#

Mikset voisi vaan ottaa käyttöön tuota Mazzimon mainitsemaa std::string-luokkaa, koska käytät C++:aa?

Blaze [23.05.2007 23:29:44]

#

kayttaja-3842 kirjoitti:

if(tuloskomento == "print"){

Et voi vertailla char-taulua noin (niitä vertaillaan strcmp-funktiolla). Ota ne std::stringit käyttöön, niitä voi.

_Pete_ [25.05.2007 08:49:10]

#

Regexp, capturing matches.

"(.*?)\((.*?))\)" tms. eli eka capturing group on kaikki ennen ekaa ( ja toka () sisällä oleva. Sen jälkeen spilttaa tokan ryhmän , ja saa erilliset argumentit.

Sweiz [29.05.2007 21:31:32]

#

String-luokkaa käyttäessä tuo on todellakin paljon helpompaa, katso vaikka:

// *** Tulkki.h
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

extern void Tulkki(string komento)
{
    if (komento.compare(0, 9, "writeline") == 0)
    {
        int Aloitus = komento.find("(");
        int Lopetus = komento.find(")");
        cout << komento.substr(Aloitus + 1, Lopetus - (Aloitus + 1));
    }
}

Ja käyttö:

#include <iostream>
#include "Tulkki.h"

using namespace std;

int main()
{
    Tulkki("writeline(Toimiiko?)");
    return 0;
}

Paljon helpompaa ja selkeämpää.
Lue lisää string-luokasta täältä.


Sivun alkuun

Vastaus

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

Tietoa sivustosta