150 likes | 245 Views
Herbert G. Mayer, PSU CS Status 7/9/2014. CS 201 Computer Systems Programming Chapter 7 “ Printing Binary Trees ”. Syllabus. Arithmetic Expressions and Trees Infix Without Parentheses Infix With Parentheses Postfix Without Parentheses Prefix Without Parentheses Interesting Examples
E N D
Herbert G. Mayer, PSU CS Status 7/9/2014 CS 201Computer Systems ProgrammingChapter 7“Printing Binary Trees”
Syllabus • Arithmetic Expressions and Trees • Infix Without Parentheses • Infix With Parentheses • Postfix Without Parentheses • Prefix Without Parentheses • Interesting Examples • Use of Postfix
Arithmetic Expressions and Trees • Three typical notations for dyadic operations: • Infix notation: write as the first the left operand, reading left-to-right, then list the dyadic operator, finally list the right operand • For CPU: Order will not work for code emission, as the CPU needs both operands for processing the operator • For humans: requires parentheses for proper operator precedence • Note exception: programming language APL • Postfix notation: write left operand first, then list the right operand, finally the operator • This order will work for code emission, as operator has both operands available at processing time • Needs no parentheses, and still obeys operator precedence • Postfix notation AKA Polish Postfix, after Jan Łukasiewicz, 1920 • Prefix notation: First list the operator, next the first (left) operand, finally the second (right) operand
Arithmetic Expressions and Trees Infix: ( a + ( x ^ c ) ) Postfix: a x c ^ + Prefix: + a ^ x c • a + x ^ c + a ^ x c ^ stands for exponentiation operator, with highest precedence: higher than * or / which in turn have higher priority than + or -
Arithmetic Expressions and Trees Infix: ( ( x – a ) / b ) Postfix: x a – b / Prefix: / – x a b • ( x – a ) / b / - b x a / stands for division operator, with higher precedence than, say, –
Arithmetic Expressions and Trees Infix: ( ( a ^ ( b – c ) ) / d ) Postfix: a b c - ^ d / Prefix: / ^ a – b c d Wrong: a ^ ( ( b – c ) / d ) • a ^ ( b – c ) / d / ^ d a - b c
Data Structure to Print Trees • Express tree and printing it via a C program • To do so, define a NodeType data structure • Thus a node needs to haver operand operator classification, and 2 possible subtrees • For practical purposes, distinguish literals from variable (i.e. symbolic names) • Represent the arithmetic expression as tree of such nodes • And define functions that traverse the tree and print operands and operators in the right order
Data Structure to Print Trees • // node has class: literal, identifier, or operator. • // Parenthesized expressions have been reduced: no ( ) • typedef enum { Literal, Identifier, Operator } NodeClass; • typedef struct NodeType * NodePtr; // forward • // actual node structure; using the forward pointers • typedef struct NodeType • { • NodeClass Class; // 3 classes. Not C++ ‘class’ • char Symbol; // stores ident or small literal • int LitVal; // if Class == Literal: its value • NodePtr Left; // left subtree • NodePtr Right; // right subtree • } s_node_tp;
Infix Without Parentheses • // Print in infix notation without parentheses ( ) • void Print_No_Paren( NodePtr Root ) • { // Print_No_Paren • if ( Root ) { • Print_No_Paren ( Root->Left ); • if ( Root->Class == Literal ) { • printf( "%d", Root->LitVal ); • }else{ • printf( "%c", Root->Symbol ); • } //end if • Print_No_Paren ( Root->Right ); • } //end if • } //end Print_No_Paren Input: ( a + x ) / b prints as: a + x / b misleading
Infix With Parentheses • // Print in infix notation with parentheses ( and ) • // though prints too many ( ) pairs • void Print_Infix( NodePtr Root ) • { // Print_Infix • if ( Root ) { • if ( Root->Class == Operator ) { • printf( "(" ); • } //end if • Print_Infix( Root->Left ); • if ( Root->Class == Literal ) { • printf( "%d", Root->LitVal ); • }else{ • printf( "%c", Root->Symbol ); • } //end if • Print_Infix( Root->Right ); • if ( Root->Class == Operator ) { • printf( ")" ); • } //end if • } //end if • } //end Print_Infix Input: ( a + x ) / b prints as: ( ( a + x ) / b ) -- OK
Postfix Without Parentheses // Print in Polish Postfix notation, no parentheses void Print_Postfix( NodePtr Root ) { // Print_Postfix if ( Root ) { Print_Postfix( Root->Left ); Print_Postfix( Root->Right ); if ( Root->Class == Literal ) { printf( "%d", Root->LitVal ); }else{ printf( "%c", Root->Symbol ); } //end if } //end if } //end Print_Postfix Input: a ^ ( b – c ) / d prints as: a b c - ^ d / -- OK
Prefix Without Parentheses // Prefix: operator executes when 2 operands found void Print_Prefix( NodePtr Root ) { // Print_Prefix if ( Root ) { if ( Root->Class == Literal ) { printf( "%d", Root->LitVal ); }else{ printf( "%c", Root->Symbol ); } //end if Print_Prefix( Root->Left ); Print_Prefix( Root->Right ); } //end if } //end Print_Prefix Input: ( a + x ) / b prints as: / + a x b -- OK
Interesting Examples • Input 1: a + b * c ^ ( x – 2 * d ) / ( e – f ) Infix: ( a + ( ( b * ( c ^ ( x – ( 2 * d ) ) ) ) / ( e – f ) ) ) Postfix: a b c x 2 d * - ^ * e f - / + Prefix: + a / * b ^ c – x * 2 d – e f Input 2: 4 / x ^ ( k – l / m ) * 8 * x - & 9 + n Infix: ( ( ( ( ( 4 / ( x ^ ( k - ( l / m ) ) ) ) * 8 ) * x ) - ( & 9 ) ) + n ) Postfix: 4 x k l m / - ^ / 8 * x * 9 & - n + Prefix: + - * * / 4 ^ x – k / l m 8 x & 9 n
Use of Postfix • Postfix, AKA Polish Postfix notation is a natural for code generation, not just for stack machines • Operands are needed first: Two for dyadic, or one for monadic operations • Once generated and available on stack, stack machine can execute the next operation • Easy for compiler writer, natural for stack machine • Stack poor for execution, as all references are through memory: top of stack • Even a GPR architecture needs both operands available somewhere (in regs) to execute operator
References • Łukasiewicz: http://www.calculator.org/Lukasiewicz.aspx • http://cslibrary.stanford.edu/110/BinaryTrees.html