1 / 53

Compiler Structures

Compiler Structures. 241-437 , Semester 1 , 2011-2012. Objective extend the expressions language compiler to generate a parse tree for the input program, and then evaluate it. 9. Creating and Evaluating a Parse Tree. Overview. 1 . The Expressions Grammar 2 . exprParse2.c

Télécharger la présentation

Compiler Structures

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Compiler Structures 241-437, Semester 1, 2011-2012 • Objective • extend the expressions language compiler to generate a parse tree for the input program, and then evaluate it 9. Creating and Evaluating a Parse Tree

  2. 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

  3. Source Program In this lecture Lexical Analyzer Front End Syntax Analyzer Semantic Analyzer Int. Code Generator concentrating on parse tree generation and evaluation Intermediate Code Code Optimizer Back End Target Code Generator Target Lang. Prog.

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

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

  6. 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

  7. 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

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

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

  10. 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.

  11. 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) left right branches

  12. 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)

  13. 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()

  14. int main(void) { nextToken(); statements(); match(SCANEOF); return 0; } 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; } main() Before and After

  15. 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()

  16. 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()

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

  18. 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 expression(); } // end of statement()

  19. 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()

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

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

  22. 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()

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

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

  25. 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()

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

  27. 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()

  28. 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()

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

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

  31. 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 value a union OR left right branches

  32. 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()

  33. Making an ID Node operTok ID "id str" id 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() no symbol table entry created yet

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

  35. 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

  36. 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.

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

  38. 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()

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

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

  41. Graphically \n \n * / 5 \n = 67 3 bing_BONG - S3 = NULL x56 * x56 2 27 2 S1 S2

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

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

  44. 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

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

  46. 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()

  47. 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

  48. 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)); :

  49. 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()

  50. 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)

More Related