17 recursion 2
play

17. Recursion 2 Input: 3 + 5 * 20 Output: 103 Input: (3 + 5) * 20 - PowerPoint PPT Presentation

Motivation: Calculator Goal: we build a command line calculator Example Input: 3 + 5 Output: 8 Input: 3 / 5 Output: 0.6 17. Recursion 2 Input: 3 + 5 * 20 Output: 103 Input: (3 + 5) * 20 Output: 160 Input: -(3 + 5) + 20 Building a Calculator,


  1. Motivation: Calculator Goal: we build a command line calculator Example Input: 3 + 5 Output: 8 Input: 3 / 5 Output: 0.6 17. Recursion 2 Input: 3 + 5 * 20 Output: 103 Input: (3 + 5) * 20 Output: 160 Input: -(3 + 5) + 20 Building a Calculator, Formal Grammars, Extended Backus Naur Output: 12 Form (EBNF), Parsing Expressions binary Operators + , - , * , / and numbers floating point arithmetic precedences and associativities like in C++ parentheses unary operator - 492 493 Naive Attempt (without Parentheses) Analyzing the Problem double lval; Example std::cin >> lval; Input: char op; while (std::cin >> op && op != ’=’) { 13 + 4 ∗ (15 − 7 ∗ 3) = double rval; std::cin >> rval; Needs to be stored such that evaluation can be performed if (op == ’+’) lval += rval; Input 2 + 3 * 3 = else if (op == ’ ∗ ’) Result 15 lval ∗ = rval; else ... } std::cout << "Ergebnis " << lval << "\n"; 494 495

  2. Analyzing the Problem Formal Grammars Alphabet: finite set of symbols Strings: finite sequences of symbols 13 + 4 ∗ (15 − 7 ∗ 3) A formal grammar defines which strings are valid. “Understanding an expression requires lookahead to upcoming symbols! We will store symbols elegantly using recursion. To describe the formal grammar, we use: We need a new formal tool (that is independent of C++ ). Extended Backus Naur Form (EBNF) 496 497 Expressions -(3-(4-5))*(3+4*5)/6 What do we need in a grammar? Number , ( Expression ) Factor - Number, -( Expression ) Factor * Factor, Factor Term Factor / Factor , ... Term + Term, Term Expression Term - Term, ... 499

  3. The EBNF for Expressions The EBNF for Expressions A factor is A term is a number, factor, an expression in parentheses or factor * factor, factor / factor, non-terminal symbol a negated factor. factor * factor * factor, factor / factor * factor, ... ... factor = unsigned_number | "(" expression ")" term = factor { " ∗ " factor | "/" factor }. | " − " factor . terminal symbol optional repetition alternative 500 501 The EBNF for Expressions Parsing factor = unsigned_number Parsing: Check if a string is valid according to the EBNF . | "(" expression ")" Parser: A program for parsing. Useful: From the EBNF we can (nearly) automatically generate a | " − " factor . parser: Rules become functions term = factor { " ∗ " factor | "/" factor }. Alternatives and options become if –statements. Nonterminial symbols on the right hand side become function calls Optional repetitions become while –statements expression = term { "+" term |" − " term }. 502 503

  4. Rules Functions (Parser) Expression is read from an input stream. factor = unsigned_number | "(" expression ")" // POST: returns true if and only if in_stream = factor ... | " − " factor . // and in this case extracts factor from in_stream bool factor (std::istream& in_stream); term = factor { " ∗ " factor | "/" factor }. // POST: returns true if and only if in_stream = term ..., // and in this case extracts all factors from in_stream bool term (std::istream& in_stream); expression = term { "+" term |" − " term }. // POST: returns true if and only if in_stream = expression ..., // and in this case extracts all terms from in_stream bool expression (std::istream& in_stream); 504 505 Functions (Parser with Evaluation) One Character Lookahead... Expression is read from an input stream. . . . to find the right alternative. // POST: leading whitespace characters are extracted from in_stream, and the first non − whitespace character // // POST: extracts a factor from in_stream // is returned (0 if there is no such character) // and returns its value char lookahead (std::istream& in_stream) double factor (std::istream& in_stream); { if (in_stream.eof()) // eof: end of file (checks if stream is finished ) // POST: extracts a term from in_stream return 0; // and returns its value in_stream >> std::ws; // skip all whitespaces double term (std::istream& in_stream); if (in_stream.eof()) return 0; // end of stream // POST: extracts an expression from in_stream return in_stream.peek(); // next character in in_stream // and returns its value } double expression (std::istream& in_stream); 506 507

  5. Cherry-Picking Evaluating Factors double factor (std :: istream& in_stream) { . . . to extract the desired character. double value; // POST: if expected matches the next lookahead then consume it if (consume(in_stream, ’(’)) { // and return true; return false otherwise value = expression (in_stream); bool consume (std::istream& in_stream, char expected) consume(in_stream, ’)’); { } else if (consume(in_stream, ’ − ’)) { if (lookahead(in_stream) == expected){ value = − factor (in_stream); in_stream >> expected; // consume one character } else { return true; in_stream >> value; } } factor = "(" expression ")" return false ; return value; } | " − " factor } | unsigned_number . 508 509 Evaluating Terms Evaluating Expressions double term (std::istream& in_stream) double expression (std :: istream& in_stream) { { double value = factor (in_stream); double value = term(in_stream); while(true){ while(true){ if (consume(in_stream, ’ ∗ ’)) if (consume(in_stream, ’+’)) value ∗ = factor(in_stream); value += term (in_stream); else if (consume(in_stream, ’ − ’)) else if (consume(in_stream, ’/’)) value /= factor(in_stream) value − = term(in_stream) else else return value; return value; } } } } term = factor { " ∗ " factor | "/" factor }. expression = term { "+" term |" − " term }. 510 511

  6. Recursion! EBNF — and it works! EBNF ( calculator.cpp , Evaluation from left to right): Factor factor = unsigned_number | "(" expression ")" | " − " factor . Term term = factor { " ∗ " factor | "/" factor }. expression = term { "+" term |" − " term }. Expression std::stringstream input ("1 − 2 − 3"); std::cout << expression (input) << "\n"; // − 4 512 513 Calculating with Rational Numbers Rational numbers ( ◗ ) are of the form n d with n and d in ❩ C++ does not provide a built-in type for rational numbers 18. Structs Goal Rational Numbers, Struct Definition We build a C++ -type for rational numbers ourselves! 514 515

  7. Vision A First Struct Invariant: specifies valid How it could (will) look like value combinations (infor- // input struct rational { mal). std::cout << "Rational number r =? "; int n; member variable ( n umerator) rational r; int d; // INV: d != 0 std::cin >> r; }; std::cout << "Rational number s =? "; rational s; member variable ( d enominator) std::cin >> s; struct defines a new type // computation and output formal range of values: cartesian product of the value ranges of std::cout << "Sum is " << r + s << ".\n"; existing types real range of values: rational � int × int . 516 517 Accessing Member Variables A First Struct: Functionality A struct defines a new type , not a variable ! struct rational { int n; // new type rational int d; // INV: d != 0 struct rational { Meaning: every object of the new type is rep- }; int n; resented by two objects of type int the ob- int d; // INV: d != 0 jects are called n and d . rational add (rational a, rational b){ }; rational result; result.n = a.n ∗ b.d + a.d ∗ b.n; // POST: return value is the sum of a and b result.d = a.d ∗ b.d; rational add (const rational a, const rational b) return result; { } rational result; result.n = a.n * b.d + a.d * b.n; = a n · b d + a d · b n r n := a n + b n result.d = a.d * b.d; r d a d b d a d · b d member access to the int objects of a . return result; } 518 519

  8. Input Vision comes within Reach ... // Input r rational r; std::cout << "Rational number r:\n"; std::cout << " numerator =? "; // computation std::cin >> r.n; const rational t = add (r, s); std::cout << " denominator =? "; std::cin >> r.d; // output std::cout << "Sum is " << t.n << "/" << t.d << ".\n"; // Input s the same way rational s; ... 520 521 Struct Definitions Struct Defintions: Examples name of the new type (identifier) struct T { struct rational_vector_3 { T 1 name 1 ; names of the underlying names of the member rational x; T 2 name 2 ; types variables . . rational y; . . . . rational z; T n name n ; }; } ; underlying types can be fundamental or user defined Range of Values of T : T 1 × T 2 × ... × T n 522 523

Recommend


More recommend