Dagens tema Dagens tema: Kodegenerering Introduksjon Enkle variable Uttrykk Tilordning Litt mer kompliserte setninger med betingelser (Alt om kodegenerering unntatt funksjoner og array-er.)
Prosjektoversikt Del-0 Del-1 Del-2 f.cless cless f.s chargenerator scanner syntax code error log f.log
Det endelige målet Formålet Vårt oppdrag er å lage en kompilator: Inndata er trerepresentasjonen av C<-programmet laget i del 1. Utdata er en fil med x86 assemblerkode. C<-program Assemblerspråk a[x+1] = 0; Kompilator cless movl %eax,(%ecx,%edx,4) Assembler as Maskinkode 00101111
Et eksempel Anta at vi har C<-koden v = 1 + 2; Disse x86-instruksjonene gjør dette: movl $1,%eax # %EAX=1 %ECX=? stack=... pushl %eax # %EAX=1 %ECX=? stack=... 1 movl $2,%eax # %EAX=2 %ECX=? stack=... 1 movl %eax,%ecx # %EAX=2 %ECX=2 stack=... 1 popl %eax # %EAX=1 %ECX=2 stack=... addl %ecx,%eax # %EAX=3 %ECX=2 stack=... movl %eax,v # v = 3 Det finnes mange mulige kodebiter som gjør det samme. I kompendiet står angitt ganske nøyaktig hvilke som skal brukes.
Metoden gencode Hvordan implementere kodegenerering Det beste er å følge samme opplegg som for å skrive ut programkoden i del 1: Kodegenerering Legg en metode gencode inn i alle klasser som representerer en del av C<-programmet (dvs er subklasse av SyntaxUnit).
Metoden gencode class WhileStatm extends Statement { Expression test; StatmList body; static WhileStatm parse(decllist decls, FuncDecl curfunc) {. void gencode() {. void printtree() {.
Konvensjoner Konvensjoner Kodegenerering blir mye enklere om vi setter opp noen fornuftige konvensjoner: Alle beregninger skal ende opp i %EAX. %ECX og %EDX er hjelperegistre. Stakken (som aksesseres via %ESP) er til mellomresultater funksjonskall Parametre aksesseres via %EBP (neste uke) (neste uke)
Hva slags variable har vi? Enkle variable Det finnes fem sorter variable i C<: Enkle Vektorer (array-er) Globale Lokale Parametre (De blå variantene tar vi neste uke.)
Generering av variable Reservasjon av variable løses med et par metoder i code-modulen: public static void genvar(string name, boolean global, int nbytes, String comment) {. (Forelest forrige gang) public static String getglobalname(string vname) { return vname;
Generering av variable abstract class Declaration extends SyntaxUnit { String name, assemblername;. abstract class VarDecl extends Declaration {. class GlobalVarDecl extends VarDecl { void gencode() { if (isarray()) { //-- To be written... else { Code.genVar(assemblerName, true, 4, "int "+name+";");.
Tilordning Setninger I kompendiet finner vi kodeskjemaer for alle setningene. Assignment v = e Beregn e med svar i %EAX movl %eax, v
Tilordning Et forslag til implementering: class AssignStatm extends Statement { Assignment assignment; void gencode() { assignment.gencode();. class Assignment extends SyntaxUnit { Variable lhs; /* "Left hand side" */ Expression rhs; /* "Right hand side" */ void gencode() { if ( det dreier seg om et array-element ) { // To be written... else { rhs.gencode(); Code.genInstr("", "movl", "%eax,"+assemblername, name+" =");.
Hvordan lagres uttrykk? Uttrykk Hvordan lager vi kode for et uttrykk som 4 * a - 17? Et uttrykk består av en liste der elementene er vekselvis operand og operator : expression <operand> 4 <operator> * <operand> a <operator> <operand> 17
Kodegenerering Dette kan implementeres slik: class Expression extends Operand { Operand firstop = null; void gencode() { firstop.gencode(); Operator opr = firstop.nextoperator; while (opr!= null) { Code.genInstr("", "pushl", "%eax", ""); opr.secondop.gencode(); opr.gencode(); opr = opr.secondop.nextoperator;.
Operander Operander Det er ganske enkelt å lage kode som legger en global enkel variabel i %EAX-registeret: v movl v,%eax Det er like enkelt for konstanter (tall eller tegn). n movl $ n,%eax ($-tegnet forteller assembleren at det er snakk om en tallkonstant.)
Operatorer Aritmetisk operatorer e 1 + e 2 Beregn e 1 med svar i %EAX pushl %eax Beregn e 2 med svar i %EAX movl %eax,%ecx popl %eax addl %ecx,%eax Ved at alle operander er innom %EAX blir det enklere å skrive kodegenereringen. Divisjon er litt vanskeligere; se tabellene i kompendiet. Hvorfor må e 1 legges på stakken?
Operatorer Sammenligninger Disse er vanskeligere å oversette siden ingen maskininstruksjoner passer helt godt. Vi er nødt til å teste og hoppe litt. Eksempel: e 1 == e 2 1 Beregn e 1. 2 Beregn e 2. 3 Sammenlign e 1 og e 2. 4 Anta at svaret er 1 (= sant). 5 Hvis sammenligningen var=, hopp over neste punkt. 6 Svaret er 0 (= usant).
Navnelapper Lokale navnelapper Når vi skal lage slike hopp, trenger vi stadig nye navnelapper. Dette kan vi få fra Code-modulen: private static int numlabels = 0; public static String getlocallabel() { return String.format(".L%04d", ++numlabels);
Sammenligninger Sammenligningsoperatorer e 1 == e 2.Ln: Beregn e 1 med svar i %EAX pushl %eax Beregn e 2 med svar i %EAX popl %ecx cmpl %eax,%ecx movl $1,%eax je.ln movl $0,%eax
Kodegenering While-setningen while ( e ) { S.Ln 1 : Beregn e med svar i %EAX.Ln 2 : cmpl $0,%eax je.ln 2 S jmp.ln 1
Komplett kode Hele koden class WhileStatm extends Statement { Expression test; StatmList body; void gencode() { String testlabel = Code.getLocalLabel(), endlabel = Code.getLocalLabel(); Code.genInstr(testLabel, "", "", "Start while-statement"); test.gencode(); Code.genInstr("", "cmpl", "$0,%eax", ""); Code.genInstr("", "je", endlabel, ""); body.gencode(); Code.genInstr("", "jmp", testlabel, ""); Code.genInstr(endLabel, "", "", "End while-statement");.
Et eksempel while (a < 10) { a = a + 1;.L0001: # Start while-statement movl a,%eax # a pushl %eax movl $10,%eax # 10 popl %ecx cmpl %eax,%ecx movl $1,%eax jl.l0003 # Test < movl $0,%eax.L0003: cmpl $0,%eax je.l0002 movl a,%eax # a pushl %eax movl $1,%eax # 1 movl %eax,%ecx popl %eax addl %ecx,%eax # Compute + movl %eax,a # a = jmp.l0001.l0002: # End while-statement
Hva vi har lært I dag Kodegenerering for uttrykk tilordninger while-setninger Neste uke Kodegenerering for array-er funksjoner og funksjonskall