[ Pobierz całość w formacie PDF ]
.Najpierw przeanalizuj kilka z poni szych klauzul case osobno, a dopiero potem zastanów sinad dzia aniem ca ej funkcji.Znak oznaczaj cy koniec wyra enia (;), nawiasy oraz operatorys obs ugiwane poprzez zwyk e zwracanie ich warto ci:case ';': // koniec wyra enia; drukowaniecase '*':case '/':case '+':case ' ':case '(':case ')':case '=':return ct={static_cast(ch)};Operacja static_cast (11.5.2) jest w tym przypadku niezb dna, poniewa nie istnieje niejaw-na konwersja typu char na Kind (8.4.1).Tylko niektóre znaki odpowiadaj warto ciom Kind,wi c musimy zagwarantowa to dla ch.Liczby s obs ugiwane w nast puj cy sposób:case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':case '8': case '9': case '.':ip >putback(ch); // wstawia pierwsz cyfr (albo.) z powrotem do strumienia wej ciowego*ip >> ct.number_value; // wczytuje liczb do ctct.kind=Kind::number;return ct;Wypisanie wszystkich klauzul case w jednej linii zamiast ka dej w osobnym wierszu nie jestdobrym pomys em, bo taki kod jest mniej czytelny.Z drugiej strony, wpisywanie ka dej cyfryw osobnej linijce jest mudne.Dzi ki temu, e operator >> ju obs uguje wczytywanie liczbzmiennoprzecinkowych do zmiennych typu double, ten kod jest bardzo prosty.Najpierwpierwszy znak (cyfra lub kropka) jest umieszczany w cin.Nast pnie warto zmiennoprze-cinkowa mo e zosta wczytana do ct.number_value.Kup książkę Poleć książkę 10.2.Kalkulator 281Je li token nie jest ko cem danych wej ciowych ani operatorem, znakiem interpunkcyjnymczy te liczb , to musi by nazw.Nazwy s obs ugiwane podobnie do liczb:default: // name, name = lub b dif (isalpha(ch)) {ip >putback(ch); // umieszcza pierwszy znak z powrotem w strumieniu wej ciowym*ip>>ct.string_value; // wczytuje a cuch do ctct.kind=Kind::name;return ct;}W ko cu mo e te wyst pi b d.Proste a zarazem ca kiem efektywne rozwi zanie na pora-dzenie sobie z b dami to napisanie funkcji error() i zwrócenie tokenu print w warto cizwrotnej tej funkcji:error("Niepoprawny token");return ct={Kind::print};Funkcja isalpha() z biblioteki standardowej (36.2.1) zosta a u yta po to, aby unikn ko-nieczno ci wymieniania ka dego znaku w osobnej klauzuli case.Je li operator >> zostanie za-stosowany do a cucha (w tym przypadku string_value), wczytuje znaki do momentu napo-tkania bia ego znaku.W zwi zku z tym u ytkownik musi po nazwie wpisa bia y znak przedoperatorem u ywaj cym tej nazwy jako argumentu.Jest to bardzo s abe rozwi zanie i b dziemymusieli jeszcze do tego wróci w sekcji 10.2.3.Poni ej znajduje si uko czona funkcja wej ciowa:Token Token_stream::g et(){char ch = 0;*ip>>ch;switch (ch) {case 0:return ct={Kind::end}; // przypisanie i zwrotcase ';': // koniec wyra enia; drukujecase '*':case '/':case '+':case ' ':case '(':case ')':case '=':return ct=={static_cast(ch)};case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':case '8': case '9': case '.':ip >putback(ch); // wstawia pierwsz cyfr (albo.) z powrotem do strumienia wej ciowego*ip >> ct.number_value; // wczytuje liczb do ctct.kind=Kind::number;return ct;default: // name, name = lub b dif (isalpha(ch)) {ip >putback(ch); // umieszcza pierwszy znak z powrotem w strumieniu wej ciowym*ip>>ct.string_value; // wczytuje a cuch do ctct.kind=Kind::name;Kup książkę Poleć książkę 282 Rozdzia 10 " Wyra eniareturn ct;}error("Niepoprawny token");return ct={Kind::print};}}Konwersja operatora na token jest bardzo prosta, bo rodzaje operatorów zosta y zdefiniowanejako warto ci ca kowitoliczbowe (10.2.1).10.2.3.Wej cie niskopoziomoweW kalkulatorze w obecnej postaci mo na znale kilka niedogodno ci.Trzeba pami ta o do-dawaniu rednika na ko cu wyra e , aby otrzyma wynik, oraz po nazwie zawsze trzebawpisa bia y znak, co równie jest uci liwe.Na przyk ad x+7 jest tylko identyfikatorem, a nieidentyfikatorem x, operatorem = i liczb 7.Aby ten zapis zosta zinterpretowany tak, jak by-my tego normalnie chcieli, trzeba by by o doda bia y znak za x: x =7.Oba problemy mo narozwi za poprzez zamian zorientowanych na typy domy lnych operacji w funkcji get() nakod wczytuj cy pojedyncze znaki.Najpierw zrównamy znaczenie znaku nowego wiersza ze rednikiem oznaczaj cym koniecwyra enia:Token Token_stream::get(){char ch;do { // pomija bia e znaki oprócz '\n'if (!ip >get(ch)) return ct={Kind::end};} while (ch!='\n' && isspace(ch));switch (ch) {case ';':case '\n':return ct={Kind::print};W kodzie tym u y em instrukcji do, która ró ni si od p tli while tylko tym, e kontrolowaneprzez ni instrukcje s wykonywane przynajmniej raz.Wywo anie ip->get(ch) wczytuje jedenznak ze strumienia wej ciowego *ip do ch.Domy lnie funkcja get() nie pomija bia ych znakówtak jak operator >>.Test if (!ip >get(ch)) ko czy si pomy lnie, gdy nie mo na wczyta ad-nego znaku z cin.W tym przypadku sesj kalkulatora ko czy zwrócenie warto ci Kind::end.Operator ! (nie) zosta u yty, bo funkcja get() zwraca true w przypadku powodzenia.Do sprawdzania, czy znak jest znakiem bia ym, mo na u ywa funkcji isspace() z biblio-teki standardowej (36.2.1).Wywo anie isspace(c) zwraca warto niezerow , je li c jest bia ymznakiem, a zero w przeciwnym przypadku.Test ten jest zaimplementowany w formie prze-szukiwania tablicy, dzi ki czemu u ycie funkcji isspace() jest wydajniejszym rozwi zaniemni samodzielne sprawdzanie poszczególnych znaków.Istniej podobne funkcje do spraw-dzania, czy znak jest cyfr (isdigit()), liter (isalpha()) oraz cyfr lub liter (isalnum()).Po pomini ciu bia ego znaku brany jest nast pny znak w celu okre lenia, jaki pojawi sitoken leksykalny.Kup książkę Poleć książkę 10.2.Kalkulator 283Problem powodowany przez wczytywanie przez operator >> znaków do a cucha do mo-mentu napotkania bia ego znaku jest rozwi zany przez wczytywanie po jednym znaku a doznalezienia znaku nie b d cego liter ani cyfr :default: // NAME, NAME= lub b dif (isalpha(ch)) {string_value = ch;while (ip >get(ch) && isalnum(ch))string_value += ch; // do cza ch na ko cu string_valueip >putback(ch);return ct={Kind::name};}Na szcz cie oba udoskonalenia mo na zaimplementowa poprzez wprowadzenie zmianw jednym lokalnym miejscu kodu.Konstruowanie programów w taki sposób, aby mo na jeby o usprawnia poprzez wprowadzanie zmian lokalnych, jest wa n cz ci projektowania.Kto mo e si obawia , e dodawanie znaków po jednym do a cucha to bardzo niewy-dajna operacja.W przypadku bardzo d ugich a cuchów rzeczywi cie by tak by o, ale wszystkienowoczesne implementacje typu string zawieraj  mechanizm optymalizacji ma ych a cu-chów (19.3.3).To oznacza, e obs uga a cuchów, jakie mog pojawi si jako nazwy w na-szym kalkulatorze (a nawet w kompilatorze), nie wymaga wykonywania kosztownych operacji.W szczególno ci u ycie krótkiego a cucha nie wymaga korzystania z pami ci wolnej.Mak-symalna liczba znaków w krótkim a cuchu jest zale na od implementacji, ale my l , e mo napowiedzie , i wynosi oko o 14.10.2.4.Obs uga b dówNigdy nie nale y zaniedbywa wykrywania i zg aszania b dów, chocia w tym programiewystarczy prosta strategia obs ugi b dów.Funkcja error() liczy b dy, drukuje informacjo b dzie i dokonuje zwrotu:int no_of_errors;double error(const string& s){no_of_errors++;cerr [ Pobierz całość w formacie PDF ]
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • przylepto3.keep.pl