• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Jak napisać własny prosty interpreter?

Object Storage Arubacloud
0 głosów
1,073 wizyt
pytanie zadane 18 lutego 2018 w C i C++ przez Hiskiel Pasjonat (22,830 p.)

Witam! Mam problem :/. Otóż potrzebuję napisać interpreter. Chodzi mi o coś takiego, że jeśli prześlę do niego np. !U3"Elo" to ma mi odesłać AdminElo. Program wysypuje się kiedy próbuję dodać więcej niż jeden "modyfikator":

void TAPInterpreter(string Title){

    /*
        Two letters are numbers - text.
        Two letters are !U - Username.
        Two letters are !C - Computer Name.
        Two letters are !P - Current Path.
        Two letters are !D - Current Disk.
        Two letters are !S - Space.
        Two letters are !_ - Pass to a new line.
        Two letters are !! - Exclamation mark.
        Two letters are !\ - Backslash.
        Two letters are !/ - Forward slash.
    */
       int addition;
    for(int i=0;i<Title.length();i++){
        if(i==0)addition = 0;
        else addition +=2;

        string str = Title.substr(0+addition,2+addition);

        if(str.compare("!U")==0){
            cout<<"!U";
        }
        else if(str.compare("!C")==0){
            cout<<"!C";
        }
        else if(str.compare("!P")==0){
            cout<<"!P";
        }
        else if(str.compare("!D")==0){
            cout<<"!D";
        }
        else if(str.compare("!S")==0){
            cout<<"!S";
        }
        else if(str.compare("!_")==0){
            cout<<"!_";
        }
        else if(str.compare("!!")==0){
            cout<<"!!";
        }
        else if(str.compare("!\\")==0){
            cout<<"!\\";
        }
        else if(str.compare("!/")==0){
            cout<<"!/";
        }
        else if(atoi(str.c_str())&&i!=Title.length()){
            int number = atoi(str.c_str());
            cout<<number;
        }
    }
}

 

Niestety nie mogę skorzystać z switch'a.

komentarz 18 lutego 2018 przez j23 Mędrzec (194,920 p.)

Niestety nie mogę skorzystać z switch'a.

Dlaczego?

komentarz 18 lutego 2018 przez Hiskiel Pasjonat (22,830 p.)
Switch nie chce przyjąć stringa.
komentarz 18 lutego 2018 przez j23 Mędrzec (194,920 p.)
edycja 18 lutego 2018 przez j23

Stringa nie, ale znak już tak:

size_t i = 0;

while(i < Title.length())
{
	if(Title.at(i) == '!')
	{
		switch(Title.at(++i))
		{
		case 'U': 	std::cout << "!U";	break;
		case 'C': 	std::cout << "!C";	break;
		case 'P': 	std::cout << "!P";	break;
		case 'D': 	std::cout << "!D";	break;
		case 'S': 	std::cout << "!S";	break;
		case '_': 	std::cout << "!_";	break;
		case '!': 	std::cout << "!!";	break;
		case '\\':	std::cout << "!\\";	break;
		case '/': 	std::cout << "!/";	break;
		default: /* błąd?? */
		}

		++i;
	}
	else
	{
		char *str_beg = &Title.at(i);
		char *str_end;
		std::cout << strtol(str_beg , &str_end, 10) << '\n';
		i += str_end - str_beg;
	}
}

 

2 odpowiedzi

0 głosów
odpowiedź 18 lutego 2018 przez Qwerty96 Stary wyjadacz (13,580 p.)
Metoda substr rzuca wyjątek, jeśli pierwszy argument przekracza długość stringa. I to się dzieje w Twoim programie.
komentarz 18 lutego 2018 przez Hiskiel Pasjonat (22,830 p.)
Ale dlaczego? Jeśli mam np. !C!D to długością jest 4. Za pierwszym razem addition jest równe 0, potem 2. Więc jest 2 i 4. Nic tu nie przekracza.. A w takim razie... Jak mam napisać taki interpreter?
komentarz 18 lutego 2018 przez Qwerty96 Stary wyjadacz (13,580 p.)
Ale pętla wykonuje się tyle razy, ile jest znaków w stringu. Za trzecim razem już masz 6, więc przekracza.

Ps. drugi parametr oznacza ilość znaków, które substr "wyciągnie", nie indeks, na którym skończy.
0 głosów
odpowiedź 18 lutego 2018 przez mokrowski Mędrzec (155,460 p.)

Na std::string, także można zrobić switch(...) ale to trochę więcej zabawy (constexpr i hash). 

To jest na tyle prosty interpreter, że wystarczy brutalne szukanie sekwencyjne. Prosty szkic:

#include <string>
#include <iostream>
#include <vector>
#include <utility>
#include <functional>

bool startsWith(const std::string& msg, const std::string& pattern) {
    return msg.find(pattern) == 0;
}

std::function<void()> selectFunction(const std::string& pattern) {
    // Komend jest tak mało że brutalne wyszukanie sekwencyjne
    // będzi wystarczająco wydajne.
    static std::vector<std::pair<const char *, std::function<void()>>> commands = {
        { "!U", []{ std::cout << "User\n"; } },
        { "!C", []{ std::cout << "Computer Name.\n"; } },
        { "!P", []{ std::cout << "Current Path.\n"; } },
        { "!D", []{ std::cout << "Current Disk.\n"; } },
        // ...
    };
    auto result = []{ std::cout << "Unknown command.\n"; };
    for(const auto& pr: commands) {
        if(startsWith(pr.first, pattern)) {
            return pr.second;
        }
    }
    return result;
}

int main() {
    std::string command;
    std::cout << "Enter command: ";
    std::cin >> command;
    // TODO: Sprawdzenie czy poprawna etc...
    selectFunction(command)();
}

Jak będziesz chciał mieć bardziej skomplikowane zachowanie (bazujące na komendzie), dodaj do funkcji komendy parametr i tyle :)

Podobne pytania

0 głosów
0 odpowiedzi 123 wizyt
pytanie zadane 26 lipca 2023 w Offtop przez reaktywny Nałogowiec (40,990 p.)
0 głosów
2 odpowiedzi 1,447 wizyt
0 głosów
2 odpowiedzi 322 wizyt
pytanie zadane 20 marca 2020 w PHP przez spicedagger Użytkownik (530 p.)

92,566 zapytań

141,420 odpowiedzi

319,615 komentarzy

61,952 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...