{{page>courses:b6b36pjc:styles#common&noheader&nofooter}} {{page>courses:b6b36pjc:styles#ukoly&noheader&nofooter}} ===== Parser 1 ===== V tomto úkolu naimplementujeme parser a vyhodnocovač matematických výrazů. Aby to bylo trochu jednodušší, nebudete muset pracovat s funkcemi (''sin'', ''cos'', etc) ani s proměnnými. ==== Operátory a jejich vlastnosti ==== Váš evaluátor musí podporovat alespoň 5 základních matematických operátorů, včetně jejich priorit a asociativity. Zároveň musí podporovat změnění asociativity a priorit pomocí závorek. ^ Operátor ^ Priorita ^ Asociativita ^ | ''^''((Exponenciace)) | 3 | Pravá | | ''*'', ''/'' | 2 | Levá | | ''+'', ''-'' | 1 | Levá | ==== Formát vstupu ==== Vstup se skládá z čísel, operátorů, závorek a blíže nespecifikovaného množství whitespace. To znamená, že ''1 + 2'' je ekvivalentní ''1+2'', ale i ''1 +2'', ''1+ 2'', ''(1 + 2)'' nebo dokonce ''%%((1) + (2))%%''. Můžete ale předpokládat, že vstup je vždy správný, to jest, neobsahuje špatně ozávorkované výrazy, například '')2 + 1('', přebytečné operátory, například ''1 + 1 +'', ani nic podobného. Potřebné hlavičkové soubory a testy jsou ke stažení {{:courses:b6b36pjc:ukoly:parser-1.zip|zde}}. ==== Příklady ==== ^ Vstup ^ Výsledek ^ | 1 + 2 | 3 | | 1 + 2 * 3 | 7 | | 1 | 1 | | 2%%^%%3%%^%%3 | 134217728 | | (2%%^%%3)%%^%%3| 512 | ==== Co odevzdat? ==== Všechny soubory, které implementují vaše řešení úlohy, specificky, pokud jste vytvořili nové ''.hpp'' soubory, tak je nezapomeňte odevzdat. Nemusíte odevzdávat ''expr.hpp'', ani žádné testovací soubory. ===== Rady ===== ==== Operátor výstupu ==== Operátor pro výpis do proudu (''%%<<%%'') netestujeme, je pouze pro vaše potřeby -- v případě chyby v testu se přes něj vypíše interní stav vaší implementace. Co přesně bude vypisovat je pouze na vás. ==== Konstruktory se dají dědit ==== Nezapomeňte, že konstruktory se dají dědit a pokud dědící třída nepřidala žádné další datové prvky, pouze chování, může být nejlepší si nechat konstruktor předka. Aby třída zdědila konstruktor předka, musí to explicitně deklarovat: class base { public: base(int x): a(2*x) {} private: int a; }; class derived : public base { public: using base::base; // derived přebírá konstruktor předka -- base }; derived d(123); // Zde se zavolá přebraný konstruktor ==== Postfix zápis ==== Jeden z nejsnažších způsobů, jak parsovat infix matematické výrazy je [[https://cs.wikipedia.org/wiki/Shunting-yard_(algoritmus)|převést]] je do [[https://cs.wikipedia.org/wiki/Postfixov%C3%A1_notace|postfix notace]], která se snadno převede na tzv. výrazový strom. ==== Užitečné hlavičky ==== Pro práci se vstupem doporučujeme použít [[http://en.cppreference.com/w/cpp/io/basic_stringstream|std::stringstream]], specificky formátovaný výstup ke čtení čísel a metod ''.peek()'' a ''.get()'', které vám umožňují se podívat na první znak a přečíst (vyjmout z proudu) první znak respektive. Pro parsování vstupů pak doporučujeme funkce z hlavičky [[http://en.cppreference.com/w/cpp/header/cctype|cctype]], kde najdete například ''isdigit'', vracející ''true'' pokud daný znak je číslo. Pro vyhodnocení výrazu se vám budou hodit funkce z hlavičky [[http://en.cppreference.com/w/cpp/header/cmath|cmath]], kde najdete například ''pow'' sloužící k exponenciaci reálných čísel.