Εισαγωγή Ειδικά Θέματα Μεταγγλωτιστών Χειμερινό Εξάμηνο / Κατασκευή compiler για την γλώσσα Minijava
Κατασκευή ενός compiler Λεκτική Ανάλυση Συντακτική Ανάλυση Σημασιολογική Ανάλυση Παραγωγή κώδικα
Sablecc 3.0b2 Χρήση αντικειμενοστραφών τεχνικών για την αυτόματη δημιουργία αυστηρά καθορισμένων συντακτικών δέντρων από τον ορισμό κάποιας γραμματικής Χρήση του Visitor Design Pattern με αποτέλεσμα περισσότερη συναρμολογισιμότητα (modularity)
Sablecc 1. Package 2. Helpers 3. States 4. Tokens 5. Ignored Tokens 6. Productions
Lexer (1) Καταστάσεις normal και comment. Για την υποστήριξη εμφωλευμένων σχολίων είναι απαραίτητο να γίνει override η μέθοδος filter της τάξης Lexer. {normal->comment, comment} comment = '/*'; {comment} comment_star = '*'; {comment} comment_slash = '/'; {comment} comment_body = [all_input_chars-['*' + '/']]*;
Lexer (2) public class CustomLexer extends Lexer { …………………… protected void filter() { if (state.equals(State.COMMENT)) { if (comment == null) { …………………………………. } else { text.append(token.getText()); // accumulate the text. if (token instanceof TComment) { count++; critical = false; } else if (token instanceof TCommentStar) { critical = true; } else if ((token instanceof TCommentSlash) && (critical = true)) { count--; critical = false; } ………………………………………
Lexer (3) …………………………………….. if (token instanceof TInteger) { try { number = Integer.parseInt(token.getText()); } catch (NumberFormatException e) { throw new RuntimeException("Integer should not exceed 32 bit signed integer."); } …………………………………….
Abstract Syntax Tree (1) program = main_class class_decl* ; main_class = [clname]:identifier [arg]:identifier statement ; class_decl = {simple} identifier var_decl* method_decl* | {extends} [newcl]:identifier [oldcl]: identifier var_decl* method_decl* ; var_decl = type identifier ; method_decl = type identifier formal* var_decl* statement* exp ; formal = type identifier ; type = {int_array} | {boolean} | {integer} | {identifier} id_literal ; statement = {block} statement* | {if} exp [ifpart]: statement [elsepart]: statement| {while} exp statement| {print} exp| {assign} identifier exp | {array_assign} identifier [index]: exp [rhs]:exp ;
Abstract Syntax Tree (2) exp = {and} [left]:exp [right]:exp | {less_than} [left]:exp [right]:exp | {plus} [left]:exp [right]:exp | {minus} [left]:exp [right]:exp | {times} [left]:exp [right]:exp | {array_lookup} exp [index]:exp | {array_length} exp | {call} exp identifier [args]:exp* | {integer_literal} integer | {true} | {false} | {identifier} id_literal | {this} | {new_array} exp | {new_object} identifier | {not} exp ; identifier = id_literal ;
Productions -> AST (1) Getting an already existing element exp_list_tail -> exp = comma exp -> exp; New alternative exp = (plus) exp plus factor -> New exp.plus(exp,factor.exp); List creation exp_list -> exp* = exp exp_list_tail -> (exp_list_tail.exp exp);
Productions -> AST (2) CST : program = main_class class_decl* {-> New program( main_class, [class_decl] ) }; AST :program = main_class class_decl* ; CST : formal_list {-> formal*} = formal formal_list_tail* {-> [formal formal_list_tail.formal]}; formal_list_tail {-> formal } = comma formal {-> formal } ; formal = type identifier {-> New formal(type, identifier) } ; AST : formal = type identifier ; CST : add_exp {-> exp } = {plus} [left]:add_exp plus [right]:mult_exp {-> New exp.plus(left.exp, right.exp) }| {minus} [left]:add_exp minus [right]:mult_exp {-> New exp.minus(left.exp, right.exp) }| {times} mult_exp {-> mult_exp.exp } ; AST :exp = {and} [left]:exp [right]:exp | {minus} [left]:exp [right]:exp
Symbol Analysis - Example Symbol Table Class 1 Method 1 Variable 1 Variable 2 Variable 3 Variable 1 Class 2 Method 1 Method 2 Variable 2 Variable 1 Variable 2 Variable 3 Variable 4 Variable 1
Symbol Analysis - Class Όνομα της τάξης Όνομα γονέα της τάξης (αν υπάρχει) Μέθοδοι Καθολικές για την τάξη μεταβλητές (Fields)
Symbol Analysis - Method Όνομα της μεθόδου Τύπος επιστροφής της μεθόδου (PType από Sablecc) Παράμετροι της μεθόδου Τοπικές μεταβλητές της μεθόδου Μετρητής
Symbol Analysis - Variable Όνομα μεταβλητής Τύπος μεταβλητής Θέση μεταβλητής. Χρήσιμο στο jas.
Semantic Analysis SymbolTableClass.java SymbolTableBuilder.java TypeCheck.java Γίνονται 3 περάσματα συνολικά. Τα δύο πρώτα για το γέμισμα του πίνακα συμβόλων με όλες τις τάξεις, μεθόδους, μεταβλητές. Στο τρίτο πέρασμα γίνονται οι υπόλοιποι σημασιολογικοί έλεγχοι. Επίσης δηλώνουμε ως global τις μεταβλητές currMethod, currClass.
Semantic Analysis (2) Τα ανιχνεύσιμα λάθη είναι : 1.Κάποια τάξη έχει ήδη δηλωθεί στον πίνακα συμβόλων 2.Ο τύπος μεταβλητής ή επιστροφής μεθόδου δεν υπάρχει 3.Κυκλική κληρονομικότητα τάξεων 4.Ο γονέας κάποιας τάξης δεν υπάρχει ως τάξη. 5.Κάποιο field variable δηλώνεται με ήδη υπάρχον όνομα 6.Κάποια παράμετρος ή τοπική μεταβλητή μεθόδου δηλώνεται με ήδη υπάρχον όνομα στην ίδια μέθοδο 7.Προσπάθεια δήλωσης μεθόδου με ήδη υπάρχον όνομα στην ίδιατάξη
Semantic Analysis (3) 8. Το όνομα κάποιας μεταβλητής σε μία έκφραση δεν έχει δηλωθεί 9. Μη σωστός τρόπος υλοποίησης override κάποιας μέθοδου του γονέα της τάξης. Υπενθυμίζεται ότι η Minijava δεν επιτρέπει overload. 10. Ο επιστρεφόμενος τύπος μιάς μεθόδου δεν εκχωρείται στον τύπο που έχει δηλωθεί στην μέθοδο. 11. Η πιθανότητα να μην έχει αρχικοποιηθεί μια μεταβλητή όταν αυτή είναι μέρος μιας έκφρασης 12. Στο ArrayLookup ( Exp[Exp] ) το πρώτο Exp πρέπει να είναι τύπου IntArray και το δεύτερο τύπου Integer 13. Στο ArrayLength ( Exp.length ) το Exp πρέπει να είναι τύπου IntArray
Semantic Analysis (4) 14. Στο NewArray ( new int [Exp] ) το Exp πρέπει να είναι τύπου Integer 15. Στους τελεστές <, +, -, * οι εκφράσεις και στα δύο μέρη τους πρέπει να είναι τύπου Integer 16. Στους τελεστές &&, ! οι εκφράσεις πρέπει να είναι τύπου Boolean 17. Στο NewObject ( new id () ) το id πρέπει να έχει δηλωθεί στον πίνακα συμβόλων ως τάξη 18. Στο CallExp ( Exp.id(ExpList) ) ο αριθμός των παραμέτρων της μεθόδου που θα κληθεί είναι μικρότερος η μεγαλύτερος από τον αριθμό παραμέτρων που πρέπει σύμφωνα με την δήλωσή της 19. Στο CallExp κάποια παράμετρος δεν μπορεί να εκχωρηθεί στον τύπο όπως προκύπτει από την δήλωση της μεθόδου στον πίνακα συμβόλων.
Semantic Analysis (5) 20. Στο CallExp η μέθοδος που θέλουμε να καλέσουμε δεν υπάρχει στην τάξη όπως προκύπτει από το Exp 21. Στο Print Statement η παράμετρος πρέπει να είναι τύπου Integer 22. Στα If και While Statements οι εκφράσεις πρέπει να είναι τύπου Boolean 23. Ασυμβατότητα τύπων στην απλή εκχώρηση 24. Στο ArrayAssign ( id[Exp] = Exp ) το id πρέπει να είναι τύπου IntArray, το πρώτο Exp τύπου Integer όπως και το δεύτερο Exp.
Semantic Analysis (6) Για κάποια από αυτά τα λάθη διακόπτεται άμεσα το typechecking με το αντίστοιχο μήνυμα λάθους Για τα περισσότερα λάθη η διαδικασία ελέγχου συνεχίζεται μέχρι το τέλος οπότε εμφανίζεται το μήνυμα λάθους και δεν προχωράμε στην επόμενη φάση. Ο λόγος είναι …….
Semantic Analysis - Implementation Το typechecking γίνεται bottom-up. Αυτό γίνεται κάνοντας override τις μεθόδους της τάξης DepthFirstAdapter. Για κάθε Exp όπως φαίνεται στο AST υπολογίζω και αποθηκεύω τον τύπο που προκύπτει σε ένα HashTable με κλειδί τον ίδιο τον κόμβο που βρίσκεται η διάσχιση κάθε στιγμή. Για HashTable χρησιμοποιώ τον πίνακα out και τις μεθόδους setOut(key,value) και getOut(key) που διαθέτει η Sablecc για αυτόν τον σκοπό ειδικά. Επομένως ξεκινώντας από τα βασικά expressions IdentifierExp, IntegerLiteralExp, TrueExp, FalseExp φτάνουμε μεχρι την ρίζα. public void outAIntegerLiteralExp(AIntegerLiteralExp node) { setOut(node, new AIntegerType()); } public void outATrueExp(ATrueExp node) { setOut(node, new ABooleanType()); } public void outAFalseExp(AFalseExp node) { setOut(node, new ABooleanType()); }
Semantic Analysis – Εxample 1 public void outAIdentifierExp(AIdentifierExp node) { String id = node.getIdLiteral().toString(); PType t = findVarType(id); setOut(node, t); …………………………………………………………… } public void outATimesExp(ATimesExp node) { PType leftType = (PType) getOut(node.getLeft()); PType rightType = (PType) getOut(node.getRight()); if (isIntegerType(leftType) && isIntegerType(rightType)) { setOut(node, new AIntegerType()); } else { System.out.println(currClass.getId() + "." + currMethod.getId() + ": " + "Both sides of multiplication must be Integer"); ok[0] = false; } }
Semantic Analysis – Εxample 2 (1) public void inAExtendsClassDecl(AExtendsClassDecl node) { String ClassName = node.getNewcl().toString().trim(); String ParentClass = node.getOldcl().toString().trim(); currClass = symtable.getClass(ClassName); int line = ((AIdentifier) node.getNewcl()).getIdLiteral().getLine(); if (iscyclic(currClass, symtable.getClass(ParentClass))) { System.out.println("Line " + line + ": " + "Cyclic inheritance detected for class" + currClass.getId()); ok[0] = false; } ……………………………………………………………………..
Semantic Analysis – Εxample 2 (2) public boolean iscyclic(minijava.symbol.Class supercl, minijava.symbol.Class subcl) { if (subcl == null) { return false; } if (subcl.getId().equals(supercl.getId())) { return true; } if (subcl.parent() == null) { return false; // root reached } return iscyclic(supercl, symtable.getClass(subcl.parent())); }
Semantic Analysis – Εxample 3 public void outAArrayAssignStatement(AArrayAssignStatement node) { String id = node.getIdentifier().toString(); PType lhs = findVarType(id); PType index = (PType) getOut(node.getIndex()); PType rhs = (PType) getOut(node.getRhs()); int line = ( (AIdentifier) node.getIdentifier()).getIdLiteral().getLine(); if (! (lhs instanceof AIntArrayType)) { System.out.println(currClass.getId() + "." + currMethod.getId() + "(Line " + line + "): " + "Left hand side variable must be an IntArray"); ok[0] = false; } if (!isIntegerType(index)) { System.out.println(currClass.getId() + "." + currMethod.getId() + "(Line " + line + "): " + "Index inside IntArray variable must be of Integer type"); ok[0] = false; }
Semantic Analysis – Εxample 4 (1) public void outAAssignStatement(AAssignStatement node) { String id = node.getIdentifier().toString(); PType lhs = findVarType(id); PType rhs = (PType) getOut(node.getExp()); int line = ( (AIdentifier) node.getIdentifier()).getIdLiteral().getLine(); if (!assignpossible(lhs, rhs)) { System.out.println(currClass.getId() + "." + currMethod.getId() + "(Line " + line + "): " + "Types do not match in assignment"); ok[0] = false; } if (currMethod.containsVar(id)) { //local vars only initcheck.put(id, new Integer(1)); }
Semantic Analysis – Εxample 4 (2) private boolean assignpossible(PType ltyp, PType rtyp) { if (ltyp.getClass() != rtyp.getClass()) { return false; } if (ltyp instanceof AIdentifierType) { // subclass variable shoud be assignable to superclass variable minijava.symbol.Class supercl, subcl; supercl = symtable.getClass( ( (AIdentifierType) ltyp).getIdLiteral(). toString().trim()); subcl = symtable.getClass( ( (AIdentifierType) rtyp).getIdLiteral(). toString().trim()); return subclass(subcl, supercl); } return true; // of same type }
Semantic Analysis – Initialization (1) private Hashtable initcheck; public void inAMethodDecl(AMethodDecl node) { ……………………………………………………………. initcheck = new Hashtable(); ……………………………………………………………. } public void outAVarDecl(AVarDecl node) { String id = node.getIdentifier().toString(); if (currMethod != null) { //local function variables initcheck.put(id, new Integer(0)); } }
Semantic Analysis – Initialization (2) public void caseAIfStatement(AIfStatement node) { ………………………………………………………………… Hashtable ifcheck = new Hashtable(); Hashtable elsecheck = new Hashtable(); ifcheck.putAll(initcheck); elsecheck.putAll(initcheck); initcheck = ifcheck; if (node.getIfpart() != null) { node.getIfpart().apply(this); } setIn(node.getIfpart(), initcheck); initcheck = elsecheck; if (node.getElsepart() != null) { node.getElsepart().apply(this); } setIn(node.getElsepart(), initcheck); Hashtable doneifcheck = (Hashtable) getIn(node.getIfpart()); Hashtable doneelsecheck = (Hashtable) getIn(node.getElsepart()); initcheck = executeAnd(doneifcheck, doneelsecheck); outAIfStatement(node); }
Translation Γίνεται χρήση του Jas για την παραγωγή Java ByteCode (.class αρχείο) Δηλώνω και εδώ μερικές global για την τάξη μεταβλητές : Οι μεταβλητές currMethod, currClass Οι μεταβλητές nclass (τύπου ClassEnv) και doit (τύπου CodeAttr) Οι μεταβλητές stackmax και stackcurr (τύπου int και οι δύο); H μεταβλητη label (τύπου int) Δυναμικά η δήλωση StackSize και Varsize Συμπλήρωση LovalVarTable Διαλέξεις 9 και 11 του Jingling Xue – University of New South Wales Java Virtual Machine Online Instruction Reference Manual - O'Reilly Associates. Όπου χρειαζόταν να δώ πως γίνεται κάτι ---> Disassembly Π.χ έστω αρχείο checkthis.java java –classpath. checkthis.java javap –c –l –classpath. checkthis
Translation – Java Types private String extractType(PType type) { if (type instanceof ABooleanType) { return "Z"; } else if (type instanceof AIntArrayType) { return "[I"; } else if (type instanceof AIntegerType) { return "I"; } else if (type instanceof AIdentifierType) { return "L" + ( (AIdentifierType) type).getIdLiteral().toString().trim() + ";“ ; } return null; }
Translation – Example 1 public void outALessThanExp(ALessThanExp node) { Label first = new Label("label" + (++label)); Label second = new Label("label" + (++label)); try { doit.addInsn(new Insn(opc_if_icmplt, first)); doit.addInsn(new Insn(opc_iconst_0)); doit.addInsn(new Insn(opc_goto, second)); doit.addInsn(first); doit.addInsn(new Insn(opc_iconst_1)); doit.addInsn(second); } catch (jasError ex) { } stackcurr--; // -2 for if_icmplt, +1 for iconst_x = -1 }
Translation – Example 2 public void inAExtendsClassDecl(AExtendsClassDecl node) { String ClassName = node.getNewcl().toString().trim(); String ParentClass = node.getOldcl().toString().trim(); currClass = symtable.getClass(ClassName); nclass = new ClassEnv(); nclass.setClass(new ClassCP(ClassName)); nclass.setSuperClass(new ClassCP(ParentClass)); nclass.setClassAccess( (short) ACC_PUBLIC); CodeAttr init = new CodeAttr(); doit = new CodeAttr(); init.addInsn(new Insn(opc_aload_0)); init.addInsn(new Insn(opc_invokenonvirtual, new MethodCP(ParentClass, " ", "()V"))); init.addInsn(new Insn(opc_return)); init.setStackSize((short)1); //aload_0 init.setVarSize((short) 1); //this nclass.addMethod( (short) 0, " ", "()V", init, null); }
Translation – Example 3 (1) public void caseAAssignStatement(AAssignStatement node) { if (node.getIdentifier() != null) { node.getIdentifier().apply(this); } String id = node.getIdentifier().toString(); PType type = findVarType(id); int position = findVarPos(id); if (position == 0) { doit.addInsn(new Insn(opc_aload_0)); if ( (++stackcurr) > stackmax) { stackmax = stackcurr; } if (node.getExp() != null) { node.getExp().apply(this); } Position > 0 αν είναι τοπική μεταβλητή
Translation – Example 3 (2) if (position > 0) { //local variables, the rest later if ( (type instanceof AIntegerType) || (type instanceof ABooleanType)) { doit.addInsn(new Insn(opc_istore, position)); } else { //AIdentifierType doit.addInsn(new Insn(opc_astore, position)); } stackcurr--; } else { String classname = currClass.getId().toString(); doit.addInsn(new Insn(opc_putfield, new FieldCP(classname, id, extractType(type)))); stackcurr = stackcurr - 2; // 1 objectref + 1 value }
Minijava Example 1 class Example1{ public static void main ( String [ ] a ) { System.out.println ( new Test1 ( ). Start (5,true) ) ; } } class Test1 extends Visitor { int fielda; public int Start(int b,boolean c) { boolean ntb ; int[] nti; int ourint; nti = new int[b]; //ourint = nti[5]; System.out.println(ourint); return nti[0] ; } } Line 7: Symbol Visitor, declared as Parent of class Test1, does not exist Test1.Start (Line 18): Variable ourint might not have been initialized Semantic Analysis has failed miserably
Minijava Example 2 class Example2{ public static void main(String[] args){ System.out.println(new B().m()); } } class A extends B{ } class B extends C{ public int m(){ int nowhere; nowhere = this.f(); /*nowhere = k;*/ return nowhere; } } class C extends A{ } Line 7: Cyclic inheritance detected for classA
Minijava Example 3 (1) class Example3{ public static void main(String[] args){ System.out.println( new Support().m()); } class Support{ public int m(){ Support a; int b; int c; a = new Support(); b = this.met( new Support()); return new Support().f(); } public int f(){ return 10; } public int g(){ return 7; } Continues
Minijava Example 3 (2) public int met(Support o){ K k; k = this.boom( new C()); k = this.loom( new C()); return k.g(); } public K boom(K k){ return k; } public K loom(C c){ return c; } } class K extends Support{ } class C extends K{ } Any Errors ? java -classpath. Example3 10