9. Creating and Evaluating a

Slides:



Advertisements
Similar presentations
Chapter 2-2 A Simple One-Pass Compiler
Advertisements

Lesson 6 CDT301 – Compiler Theory, Spring 2011 Teacher: Linus Källberg.
CPSC 388 – Compiler Design and Construction
Chapter 8 Intermediate Code Generation. Intermediate languages: Syntax trees, three-address code, quadruples. Types of Three – Address Statements: x :=
Compilers: Parse Tree/9 1 Compiler Structures Objective – –extend the expressions language compiler to generate a parse tree for the input program,
Abstract Syntax Trees Compiler Baojian Hua
Chapter 2 A Simple Compiler
Yu-Chen Kuo1 Chapter 2 A Simple One-Pass Compiler.
CH2.1 CSE4100 Chapter 2: A Simple One Pass Compiler Prof. Steven A. Demurjian Computer Science & Engineering Department The University of Connecticut 371.
2.2 A Simple Syntax-Directed Translator Syntax-Directed Translation 2.4 Parsing 2.5 A Translator for Simple Expressions 2.6 Lexical Analysis.
CPSC 388 – Compiler Design and Construction Parsers – Context Free Grammars.
1 Chapter 2 A Simple Compiler. 2 Outlines 2.1 The Structure of a Micro Compiler 2.2 A Micro Scanner 2.3 The Syntax of Micro 2.4 Recursive Descent Parsing.
Compilers: topDown/5 1 Compiler Structures Objective – –look at top-down (LL) parsing using recursive descent and tables – –consider a recursive.
COP4020 Programming Languages
Compilers: Attr. Grammars/8 1 Compiler Structures Objective – –describe semantic analysis with attribute grammars, as applied in yacc and recursive.
Semantic Analysis (Generating An AST) CS 471 September 26, 2007.
1 Week 4 Questions / Concerns Comments about Lab1 What’s due: Lab1 check off this week (see schedule) Homework #3 due Wednesday (Define grammar for your.
Chapter 1 Introduction Dr. Frank Lee. 1.1 Why Study Compiler? To write more efficient code in a high-level language To provide solid foundation in parsing.
1 Programming Languages Tevfik Koşar Lecture - II January 19 th, 2006.
Lexical Analysis - An Introduction. The Front End The purpose of the front end is to deal with the input language Perform a membership test: code  source.
Compilers: IC/10 1 Compiler Structures Objective – –describe intermediate code generation – –explain a stack-based intermediate code for the expression.
Lesson 3 CDT301 – Compiler Theory, Spring 2011 Teacher: Linus Källberg.
Topic #2: Infix to Postfix EE 456 – Compiling Techniques Prof. Carl Sable Fall 2003.
CPS 506 Comparative Programming Languages Syntax Specification.
Abstract Syntax Trees Compiler Baojian Hua
Compilers: lex analysis/2 1 Compiler Structures Objective – –what is lexical analysis? – –look at a lexical analyzer for a simple 'expressions'
Compilers: Overview/1 1 Compiler Structures Objective – –what are the main features (structures) in a compiler? , Semester 1,
. n COMPILERS n n AND n n INTERPRETERS. -Compilers nA compiler is a program thatt reads a program written in one language - the source language- and translates.
Compiler Construction By: Muhammad Nadeem Edited By: M. Bilal Qureshi.
Lesson 4 CDT301 – Compiler Theory, Spring 2011 Teacher: Linus Källberg.
LECTURE 3 Compiler Phases. COMPILER PHASES Compilation of a program proceeds through a fixed series of phases.  Each phase uses an (intermediate) form.
LECTURE 11 Semantic Analysis and Yacc. REVIEW OF LAST LECTURE In the last lecture, we introduced the basic idea behind semantic analysis. Instead of merely.
More yacc. What is yacc – Tool to produce a parser given a grammar – YACC (Yet Another Compiler Compiler) is a program designed to compile a LALR(1) grammar.
CS 404Ahmed Ezzat 1 CS 404 Introduction to Compiler Design Lecture 1 Ahmed Ezzat.
Compilers: Bottom-up/6 1 Compiler Structures Objective – –describe bottom-up (LR) parsing using shift- reduce and parse tables – –explain how LR.
CC410: System Programming Dr. Manal Helal – Fall 2014 – Lecture 12–Compilers.
Chapter4 Syntax-Directed Translation Introduction : 1.In the lexical analysis step, each token has its attribute , e.g., the attribute of an id is a pointer.
Introduction to Parsing
Compiler Design (40-414) Main Text Book:
CS 163 Data Structures Chapter 10 Symbolic Differentiation
A Simple Syntax-Directed Translator
Lecture #12 Parsing Types.
Herbert G. Mayer, PSU CS status 7/29/2013
Compiler Construction
Abstract Syntax Trees Lecture 14 Mon, Feb 28, 2005.
CS 536 / Fall 2017 Introduction to programming languages and compilers
Trees.
Bison: Parser Generator
Syntax Analysis Sections :.
Syntax-Directed Definition
Chapter 2: A Simple One Pass Compiler
CMPE 152: Compiler Design September 13 Class Meeting
CSE401 Introduction to Compiler Construction
Compilers B V Sai Aravind (11CS10008).
R.Rajkumar Asst.Professor CSE
Designing a Predictive Parser
Compiler design.
Compiler Structures 8. Attribute Grammars Objectives
Trees.
Lexical and Syntax Analysis
Compiler Structures 3. Lex Objectives , Semester 2,
Compiler Structures 5. Top-down Parsing Objectives
Compiler Structures 4. Syntax Analysis Objectives
The Recursive Descent Algorithm
Compiler Structures 2. Lexical Analysis Objectives
10. Intermediate Code Generation
High-Level Programming Language
Lexical and Syntax Analysis
Compiler Structures 1. Overview Objective
Compiler Structures 11. IC Generation: Control Structures Objectives
Presentation transcript:

9. Creating and Evaluating a Compiler Structures 242-437, Semester 2, 2018-2019 9. Creating and Evaluating a Parse Tree Objective extend the expressions language compiler to generate a parse tree for the input program, and then evaluate it

Overview 1. The Expressions Grammar 2. exprParse2.c 3. Parse Tree Data Structures 4. Revised Parse Functions 5. Tree Building 6. Tree Printing 7. Tree Evaluation

In this lecture Front End Back End Source Program Lexical Analyzer Syntax Analyzer In this lecture Semantic Analyzer Int. Code Generator concentrating on parse tree generation and evaluation Intermediate Code Code Optimizer Back End As I said earlier, there will be 5 homeworks, each of which will contribute to 5% of your final grade. You will have at least 2 weeks to complete each of the homeworks. Talking about algorithms really helps you learn about them, so I encourage you all to work in small groups. If you don’t have anyone to work with please either e-mail me or stop by my office and I will be sure to match you up with others. PLEASE make sure you all work on each problem; you will only be hurting yourself if you leach off of your partners. Problems are HARD! I will take into account the size of your group when grading your homework. Later in the course I will even have a contest for best algorithm and give prizes out for those who are most clever in their construct. I will allow you one late homework. You *must* write on the top that you are taking your late. Homework 1 comes out next class. Target Code Generator Target Lang. Prog.

1. The Expressions Grammar Its LL(1) grammar: Stats => ( [ Stat ] \n )* Stat => let ID = Expr | Expr Expr => Term ( (+ | - ) Term )* Term => Fact ( (* | / ) Fact ) * Fact => '(' Expr ')' | Int | Id

An Expressions Program (test3.txt) 5 + 6 let x = 2 3 + ( (x*y)/2) // comments // y let x = 5 let y = x /0 // comments

exprParse2.c A recursive descent parser using the expressions language. This version of the parser differs from exprParse1.c by having the parse functions (e.g. statements(), statement()) create a parse tree as they execute. continued

There's a new printTree() function which prints the final tree, and evalTree() which evaluates it. Usage: $ gcc -Wall -o exprParse2 exprParse2.c $ ./exprParse2 < test1.txt

Output for test1.txt \n \n = printed tree; same as y = + x 2 3 x let x = 2 let y = 3 + x > exprParse2 < test1.txt \n NULL = x 2 y + 3 \n \n = printed tree; same as y NULL = + x 2 3 x continued

evaluation of the parse tree x being declared x = 2 == 2 y being declared y = 5 == 5 > evaluation of the parse tree

3. Parse Tree Data Structures typedef struct TreeNode { Token operTok; union { char *id; int value; struct {struct TreeNode *left, *right;} branches; } u; } Tree; A tree is made from TreeNodes.

Graphically one of ID, INT, NEWLINE, ASSIGNOP, PLUSOP, MINUSOP, MULTOP, DIVOP TreeNode operTok id variable name (for ID) OR a union, u value integer (for INT) OR children pointers of this node (used by NEWLINE, ASSIGNOP, PLUSOP, MINUSOP, MULTOP, DIVOP) branches left right

Macros for Using TreeNode Fields #define TreeOper(t) ((t)->operTok) #define TreeID(t) ((t)->u.id) #define TreeValue(t) ((t)->u.value) #define TreeLeft(t) ((t)->u.branches.left) #define TreeRight(t) ((t)->u.branches.right)

4. Revised Parse Functions The parse functions have the same 'shape' as the ones in exprParse0.c, but now call tree building functions, and return a Tree result. Functions: main(), statements(), statement(), expression(), term(), factor()

main() Before and After int main(void) // parse, then print and evaluate the resulting tree { Tree *t; nextToken(); t = statements(); match(SCANEOF); printTree(t, 0); printf("\n\n"); evalTree(t); return 0; } int main(void) { nextToken(); statements(); match(SCANEOF); return 0; }

statements() Before and After with no semantic actions void statements(void) // statements ::= { [ statement] '\n' } { dprint("Parsing statements\n"); while (currToken != SCANEOF) { if (currToken != NEWLINE) statement(); match(NEWLINE); } } // end of statements()

Tree. statements(void) { Tree. t,. left, Tree *statements(void) { Tree *t, *left, *statTree; left = NULL; dprint("Parsing statements\n"); while (currToken != SCANEOF) { if (currToken != NEWLINE) statTree = statement(); else statTree = NULL; match(NEWLINE); if (statTree != NULL) { t = makeTreeNode(NEWLINE, left, statTree); left = t; } return left; } // end of statements()

Tree Structure for statements A statements sequence: s1 \n1 s2 \n2 s3 \n3 becomes: \n3 \n2 s3 \n1 s2 s1 NULL

statement() Before and After with no semantic actions void statement(void) // statement ::= ( 'let' ID '=' EXPR ) | EXPR { if (currToken == LET) { match(LET); match(ID); match(ASSIGNOP); expression(); } else } // end of statement()

Tree. statement(void) { Tree. t,. idTree, Tree *statement(void) { Tree *t, *idTree, *exprTree; dprint("Parsing statement\n"); if (currToken == LET) { match(LET); idTree = matchId(); // build tree node, not symbol table entry match(ASSIGNOP); exprTree = expression(); t = makeTreeNode(ASSIGNOP, idTree, exprTree); } else // expression t = expression(); return t; } // end of statement()

Tree Structures for statement = or expr tree ID node expr tree

expression() Before and After with no semantic actions void expression(void) // expression ::= term ( ('+'|'-') term )* { term(); while((currToken == PLUSOP) || (currToken == MINUSOP)) { match(currToken); } } // end of expression()

Tree. expression(void) { Tree. t,. left, Tree *expression(void) { Tree *t, *left, *right; int isAddOp; dprint("Parsing expression\n"); left = term(); while((currToken == PLUSOP)||(currToken == MINUSOP)) { isAddOp = (currToken == PLUSOP) ? 1 : 0; nextToken(); right = term(); if (isAddOp == 1) // addition t = makeTreeNode(PLUSOP, left, right); else // subtraction t = makeTreeNode(MINUSOP, left, right); left = t; } return left; } // end of expression()

Tree Structure for expression An expression sequence: t1 +1 t2 - t3 +2 t4 becomes: +2 - t4 +1 t3 t2 t1

term() Before and After with no semantic actions void term(void) // term ::= factor ( ('*'|'/') factor )* { factor(); while((currToken == MULTOP) || (currToken == DIVOP)) { match(currToken); } } // end of term()

Tree. term(void) { Tree. t,. left, Tree *term(void) { Tree *t, *left, *right; int isMultOp; dprint("Parsing term\n"); left = factor(); while((currToken == MULTOP) || (currToken == DIVOP)) { isMultOp = (currToken == MULTOP) ? 1 : 0; nextToken(); right = factor(); if (isMultOp == 1) // multiplication t = makeTreeNode(MULTOP, left, right); else // division t = makeTreeNode(DIVOP, left, right); left = t; } return left; } // end of term()

Tree Structure for term An term sequence: f1 *1 f2 / f3 *2 f4 becomes: *2 / f4 *1 f3 f2 f1

factor() Before and After with no semantic actions void factor(void) // factor ::= '(' expression ')' | INT | ID { if(currToken == LPAREN) { match(LPAREN); expression(); match(RPAREN); } else if(currToken == INT) match(INT); else if (currToken == ID) match(ID); else syntax_error(currToken); } // end of factor()

Tree. factor(void) { Tree Tree *factor(void) { Tree *t = NULL; dprint("Parsing factor\n"); if(currToken == LPAREN) { match(LPAREN); t = expression(); match(RPAREN); } else if(currToken == INT) { t = makeIntLeaf(currTokValue); match(INT); else if (currToken == ID) t = matchId(); // do not access symbol table else syntax_error(currToken); return t; } // end of factor()

Match an ID (Extended) Tree *matchId(void) { Tree *t; if (currToken == ID) t = makeIDLeaf(tokString); match(ID); return t; } // end of matchID()

Tree Structure for factor There are three possible nodes: tree node INT node ID node or or

5. Tree Building TreeNode The nodes in a parse tree are connected by the parse functions. A tree node can have three different shapes: operTok id OR a union value OR branches left right

Making a Tree Node Tree *treeMalloc(void) // a tree node with no fields specified { Tree *t; t = (Tree *) malloc( sizeof(Tree) ); if(t == NULL) { /* out of memory? */ perror("Tree Node not made; out of memory"); exit(1); } return t; } // end of treeMalloc()

Making an ID Node operTok ID "id str" id no symbol table entry Tree *makeIDLeaf(char *id) { Tree *t; t = treeMalloc(); TreeOper(t) = ID; TreeID(t) = (char *) malloc(strlen(id)+1); strcpy(TreeID(t), id); return t; } // end of makeIDLeaf() id "id str" no symbol table entry created yet

Making an INT Node operTok INT integer value Tree *makeIntLeaf(int value) { Tree *t; t = treeMalloc(); TreeOper(t) = INT; TreeValue(t) = value; return t; } // end of makeIntLeaf() value integer

Making a Node with Children Tree *makeTreeNode(Token op, Tree *left, Tree *right) /* Build an internal tree node, which contains an operator and points to two subtrees.*/ { Tree *t; t = treeMalloc(); TreeOper(t) = op; TreeLeft(t) = left; TreeRight(t) = right; return t; } // end of makeTreeNode() operTok op branches left right

6. Tree Printing The printTree() function recurses over the tree, and does three different things depending on the three possible 'shapes' for a tree node. It includes an indent counter, which is used to print spaces (indents) in front of the node information.

void printTree(Tree *t, int indent) // print a tree, indenting by indent spaces { printIndent(indent); if (t == NULL) { printf("NULL\n"); return; } : continued

Token tok = TreeOper(t); if (tok == INT) printf("%d\n", TreeValue(t)); else if (tok == ID) printf("%s\n", TreeID(t)); else { // operator if (tok == NEWLINE) printf("\\n\n"); // show the \n else printf("%s\n", tokSyms[tok]); printTree(TreeLeft(t), indent+2); printTree(TreeRight(t), indent+2); } } // end of printTree()

void printIndent(int n) { int spaces; for(spaces = 0; spaces void printIndent(int n) { int spaces; for(spaces = 0; spaces != n; spaces++) putchar(' '); } // end of printIndent()

Tree Printing Examples > exprParse2 < test2.txt \n NULL = x56 2 bing_BONG - * 27 * 5 / 67 3 let x56 = 2 let bing_BONG = (27 * 2) - x56 5 * (67 / 3)

Graphically \n \n * / 5 \n = 67 3 bing_ BONG - S3 NULL = x56 * x56 2 27 2 S1 S2

test3.txt 5 + 6 let x = 2 3 + ( (x*y)/2) // comments // y let x = 5 let y = x /0 // comments

> exprParse2 < test3.txt \n NULL + 5 6 = x 2 / * x y 2 = 5

7. Tree Evaluation Tree evaluation works in two stages: evalTree() searches over the tree looking for subtrees which start with an operator which is not NEWLINE these subtrees are evaluated by eval(), using the operators in their nodes

Finding non-NEWLINEs \n evalTree() used here \n * / 5 \n = 67 3 bing_ BONG - NULL = x56 * x56 2 27 2 eval() used here

Code void evalTree(Tree *t) { if (t == NULL) return; Token tok = TreeOper(t); if (tok == NEWLINE) { evalTree( TreeLeft(t) ); evalTree( TreeRight(t) ); } else printf("== %d\n", eval(t)); } // end of evalTree()

be one of ID, INT, ASSIGNOP, PLUSOP, MINUSOP, The operator can be one of ID, INT, ASSIGNOP, PLUSOP, MINUSOP, MULTOP, DIVOP int eval(Tree *t) { SymbolInfo *si; if (t == NULL) return 0; Token tok = TreeOper(t); if (tok == ID) { si = getIDEntry( TreeID(t) ); // lookup ID in symbol table return si->value; } : 7 possibilities continued

else if (tok == INT) return TreeValue(t); else if (tok == ASSIGNOP) { // id = expr si = evalID(TreeLeft(t)); //add ID to sym. table int result = eval(TreeRight(t)); si->value = result; printf("%s = %d\n", si->id, result); return result; } else if (tok == PLUSOP) return eval(TreeLeft(t)) + eval(TreeRight(t)); else if (tok == MINUSOP) return eval(TreeLeft(t)) - eval(TreeRight(t)); :

else if (tok == MULTOP) return eval(TreeLeft(t)) else if (tok == MULTOP) return eval(TreeLeft(t)) * eval(TreeRight(t)); else if (tok == DIVOP) { int right = eval(TreeRight(t)); if (right == 0) { printf("Error: Div by 0; using 1 instead\n"); return eval(TreeLeft(t)); } else return eval(TreeLeft(t)) / right; return 0; // shouldn't reach here } // end of eval()

this function finds or creates a symbol table entry for the id, and SymbolInfo *evalID(Tree *t) { char *id = TreeID(t); return getIDEntry(id); // create sym. table entry for id } // end of evalID() this function finds or creates a symbol table entry for the id, and return a pointer to the entry (same as in exprParse1.c)

Evaluation Examples let x = 2 let y = 3 + x $ ./exprParse2 < test1.txt : x declared x = 2 == 2 y declared y = 5 == 5

// test2.txt example let x56 = 2 let bing_BONG = (27 * 2) - x56 $ ./exprParse2 < test2.txt : x56 declared x56 = 2 == 2 bing_BONG declared bing_BONG = 52 == 52 == 110 // test2.txt example let x56 = 2 let bing_BONG = (27 * 2) - x56 5 * (67 / 3)

5 + 6 let x = 2 3 + ( (x*y)/2) // comments // y let x = 5 let y = x /0 $ ./exprParse2 < test3.txt : == 11 x declared x = 2 == 2 y declared == 3 x = 5 == 5 Error: Division by zero; using 1 instead y = 5