Programowanie. Teoria i praktyka z wykorzystaniem C++
Programowanie. Teoria i praktyka z wykorzystaniem C++ Programowanie. Teoria i praktyka z wykorzystaniem C++
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.
- Page 1 and 2: Programowanie. Teoria i praktyka z
- Page 3 and 4: 4 SPIS TRECI Rozdzia 1. Komputery,
- Page 5 and 6: 6 SPIS TRECI Rozdzia 6. Pisanie pro
- Page 7 and 8: 8 SPIS TRECI Cz II Wejcie i wyjcie
- Page 9 and 10: 10 SPIS TRECI 14.2. Klasa Shape 448
- Page 11 and 12: 12 SPIS TRECI 18.5.3. Inicjowanie t
- Page 13 and 14: 14 SPIS TRECI 22.2. Krótka histori
- Page 15 and 16: 16 SPIS TRECI 26.3.3. Algorytmy i n
- Page 17 and 18: 18 SPIS TRECI Dodatek D Instalowani
- Page 19 and 20: 176 ROZDZIA 6 • PISANIE PROGRAMU
- Page 21 and 22: 178 ROZDZIA 6 • PISANIE PROGRAMU
- Page 23 and 24: 180 ROZDZIA 6 • PISANIE PROGRAMU
- Page 25 and 26: 182 ROZDZIA 6 • PISANIE PROGRAMU
- Page 27 and 28: 184 ROZDZIA 6 • PISANIE PROGRAMU
- Page 29 and 30: 186 ROZDZIA 6 • PISANIE PROGRAMU
- Page 31 and 32: 188 ROZDZIA 6 • PISANIE PROGRAMU
- Page 33 and 34: 190 ROZDZIA 6 • PISANIE PROGRAMU
- Page 35 and 36: 192 ROZDZIA 6 • PISANIE PROGRAMU
- Page 37 and 38: 194 ROZDZIA 6 • PISANIE PROGRAMU
- Page 39 and 40: 196 ROZDZIA 6 • PISANIE PROGRAMU
- Page 41 and 42: 198 ROZDZIA 6 • PISANIE PROGRAMU
- Page 43 and 44: 200 ROZDZIA 6 • PISANIE PROGRAMU
- Page 45 and 46: 202 ROZDZIA 6 • PISANIE PROGRAMU
- Page 47 and 48: 204 ROZDZIA 6 • PISANIE PROGRAMU
- Page 49 and 50: 206 ROZDZIA 6 • PISANIE PROGRAMU
- Page 51: 208 ROZDZIA 6 • PISANIE PROGRAMU
- Page 55 and 56: w i c z e n i a 212 ROZDZIA 6 • P
- Page 57 and 58: 214 ROZDZIA 6 • PISANIE PROGRAMU
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.