Programowanie. Teoria i praktyka z wykorzystaniem C++

Programowanie. Teoria i praktyka z wykorzystaniem C++ Programowanie. Teoria i praktyka z wykorzystaniem C++

pdf.helion.pl
from pdf.helion.pl More from this publisher
16.07.2014 Views

6.8. STRUMIENIE TOKENÓW 209 Sowo kluczowe void (oznaczajce „nic”) wskazuje, e funkcja putback() nie zwraca adnej wartoci. Aby upewni si, e funkcja ta nie zostanie wywoana dwa razy bez odczytania (za pomoc funkcji get()) tego, co zostao zapisane w strumieniu midzy tymi wywoaniami, mona doda specjalny test: void Token_stream::putback(Token t) { if (full) error("Wywoanie funkcji putback(), gdy bufor jest peny."); buffer = t; // Kopiuje t do bufora. full = true; // Bufor jest peny. } Test skadowej full polega na sprawdzeniu warunku wstpnego: „Nie ma adnego tokenu w buforze”. 6.8.2. Wczytywanie tokenów Ca prawdziw prac wykonuje funkcja get(). Jeli w zmiennej Token_stream::buffer nie ma tokenu, funkcja ta musi wczyta znaki ze strumienia cin i zoy z nich tokeny: Token Token_stream::get() { if (full) { // Sprawdzenie, czy jest gotowy token. // Usunicie tokenu z bufora. full=false; return buffer; } char ch; cin >> ch; // Uwaga: >> pomija biae znaki (spacje, nowe wiersze, tabulatory itp.). } switch (ch) { case ';': // drukowanie case 'k': // koniec case '(': case ')': case '+': case '–': case '*': case '/': case '%': return Token(ch); // Kady znak reprezentuje sam siebie. case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { cin.putback(ch); // Wstawia cyfr z powrotem do strumienia wejciowego. double val; cin >> val; // Wczytuje liczb zmiennoprzecinkow. return Token('8',val); // '8' reprezentuje „liczb”. } default: error("Nieprawidowy token."); }

210 ROZDZIA 6 • PISANIE PROGRAMU Przeanalizujemy szczegóowo funkcj get(). Najpierw sprawdza, czy w buforze jest token. Jeli tak, zwraca go: if (full) { // Sprawdzenie, czy jest gotowy token. // Usunicie tokenu z bufora. full=false; return buffer; } Znakami musimy zajmowa si tylko wówczas, gdy full ma warto false (tzn. nie ma tokenu w buforze). W takim przypadku wczytujemy znak i postpujemy z nim odpowiednio do potrzeb. Szukamy nawiasów, operatorów i liczb. Jakikolwiek inny znak powoduje wywoanie funkcji error(), która zamyka program: default: error("Nieprawidowy token."); } Funkcja error() zostaa opisana w rozdziale 5.6.3 i jest dostpna w pliku nagówkowym std_lib_facilities.h. Musielimy zdecydowa si na jaki sposób reprezentowania kadego rodzaju tokenu, tzn. trzeba byo dobra wartoci dla skadowej kind. Dla uproszczenia i uatwienia debugowania zdecydowalimy si, e nawiasy i operatory same bd reprezentowa swój rodzaj tokenu. Dziki temu ich przetwarzanie jest bardzo atwe: case '(': case ')': case '+': case '–': case '*': case '/': return Token(ch); // Kady znak reprezentuje sam siebie. Mówic szczerze, w pierwszej wersji programu zapomnielimy o znakach: ';' oznaczajcym drukowanie i 'k' oznaczajcym koniec programu. Dodalimy je, dopiero gdy byy potrzebne w drugiej wersji. 6.8.3. Wczytywanie liczb Zostay nam jeszcze liczby, z którymi wcale tak atwo nie pójdzie. Jak dowiedzie si, jaka jest warto 123? To tyle samo, co 100+20+3, ale co zrobi z 12.34? Jest te pytanie, czy zezwala na stosowanie notacji naukowej, np. 12.34e5. Aby poradzi sobie z tym wszystkim, moglibymy potrzebowa wielu godzin, a nawet dni. Na szczcie nie jest tak le. Strumienie w C++ „wiedz”, jak wygldaj literay, i potrafi zamienia je na wartoci typu double. Musimy tylko znale sposób na zmuszenie strumienia cin do robienia tego w funkcji get(): case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8':case '9': { cin.putback(ch); // Wstawia cyfr z powrotem do strumienia wejciowego. double val; cin >> val; // Wczytuje liczb zmiennoprzecinkow. return Token('8',val); // '8' reprezentuje „liczb”. } Decyzja o wyborze znaku '8' do reprezentowania „liczb” w tokenach zostaa podjta arbitralnie.

210 ROZDZIA 6 • PISANIE PROGRAMU<br />

Przeanalizujemy szczegóowo funkcj get(). Najpierw sprawdza, czy w buforze jest token.<br />

Jeli tak, zwraca go:<br />

if (full) { // Sprawdzenie, czy jest gotowy token.<br />

// Usunicie tokenu z bufora.<br />

full=false;<br />

return buffer;<br />

}<br />

Znakami musimy zajmowa si tylko wówczas, gdy full ma warto false (tzn. nie ma tokenu<br />

w buforze). W takim przypadku wczytujemy znak i postpujemy z nim odpowiednio do potrzeb.<br />

Szukamy nawiasów, operatorów i liczb. Jakikolwiek inny znak powoduje wywoanie funkcji<br />

error(), która zamyka program:<br />

default:<br />

error("Nieprawidowy token.");<br />

}<br />

Funkcja error() zostaa opisana w rozdziale 5.6.3 i jest dostpna w pliku nagówkowym<br />

std_lib_facilities.h.<br />

Musielimy zdecydowa si na jaki sposób reprezentowania kadego rodzaju tokenu, tzn.<br />

trzeba byo dobra wartoci dla skadowej kind. Dla uproszczenia i uatwienia debugowania<br />

zdecydowalimy si, e nawiasy i operatory same bd reprezentowa swój rodzaj tokenu.<br />

Dziki temu ich przetwarzanie jest bardzo atwe:<br />

case '(': case ')': case '+': case '–': case '*': case '/':<br />

return Token(ch); // Kady znak reprezentuje sam siebie.<br />

Mówic szczerze, w pierwszej wersji programu zapomnielimy o znakach: ';' oznaczajcym<br />

drukowanie i 'k' oznaczajcym koniec programu. Dodalimy je, dopiero gdy byy potrzebne<br />

w drugiej wersji.<br />

6.8.3. Wczytywanie liczb<br />

Zostay nam jeszcze liczby, z którymi wcale tak atwo nie pójdzie. Jak dowiedzie si, jaka jest<br />

warto 123? To tyle samo, co 100+20+3, ale co zrobi z 12.34? Jest te pytanie, czy zezwala<br />

na stosowanie notacji naukowej, np. 12.34e5. Aby poradzi sobie z tym wszystkim, moglibymy<br />

potrzebowa wielu godzin, a nawet dni. Na szczcie nie jest tak le. Strumienie w <strong>C++</strong><br />

„wiedz”, jak wygldaj literay, i potrafi zamienia je na wartoci typu double. Musimy tylko<br />

znale sposób na zmuszenie strumienia cin do robienia tego w funkcji get():<br />

case '.':<br />

case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':<br />

case '8':case '9':<br />

{ cin.putback(ch); // Wstawia cyfr z powrotem do strumienia wejciowego.<br />

double val;<br />

cin >> val;<br />

// Wczytuje liczb zmiennoprzecinkow.<br />

return Token('8',val); // '8' reprezentuje „liczb”.<br />

}<br />

Decyzja o wyborze znaku '8' do reprezentowania „liczb” w tokenach zostaa podjta arbitralnie.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!