Obligatorisk oppgave 2 i INF5110 v�ren 2009
Merk: Dette er en tidlig utgave. Det kan komme presiseringer.
Dette er den andre av to oppgaver v�ren 2009. Den bygger videre p� det som er gjort i oblig 1.
Innhold
- Hensikten med oppgaven
- Selve oppgaven
- Frist
- Virtuell maskin og byte-kode
- Testsuite
- Gjennomf�ring og levering
Hensikten med oppgaven
Tanken bak denne oppgaven er at man skal f� enn� mer praktisk erfaring med hva som gj�res i en kompilator, nemlig:
- Analyse av et programs statiske semantikk.
- Anvendelse av et abstrakt syntakstree.
- Typesjekking, sjekking av bruk av navn og blokkstrtuktur i spr�k.
- Kodegenerering til en bytekode fra et abstrakt syntakstre og litt om interpretering av bytekode.
Oppgaven
Del to av den obligatoriske oppgaven bygger p� den f�rste delen, og g�r ut p� � implementere kravene til statisk semantikk, beskrevet i spr�knotatet. Resultatene fra kj�ring av en testsuite skal leveres. I tillegg skal det ogs� leveres en listing av byte-koden for eksempelprogrammet RunMe.d.
- Ta utgangspunkt i et abstrakt syntakstre og sjekke om treet oppfyller alle kravene gitt av spr�kets semantikk.
- Gj�re om p� det treet som ble laget i oblig 1 om n�dvendig og lage en oversiktlig kode som benytter abstrakte klasser og funksjoner.
- Dersom man finner feil, gi en kort melding, som skrives ut p� skjermen.
- Returnere en verdi fra kompilatoren som forteller om koden var godkjent (0), om det var syntaksfeil (1) eller om det var semantikkfeil (2).
- Generere byte-kode ved hjelp av det utdelte biblioteket for byte-kode (Se pakken bytecode.* og underpakkene og spesielt klassen CodeFile). Legg merke til at det er begrensninger i byte-koden, slik at det ikke er mulig � generere byte-kode for alle eksemplene i katalogen test. Les mer om det under Virtuell maskin og byte-kode.
Frist
Fristen er fredag 8. mai.
Virtuell maskin og byte-kode
Den virtuelle maskinen og byte-kode er grundig beskrevet i notat om bytecode og interpreter.
Det er laget en pakke med klasser for � lage byte-kode. For � lage byte-kode, opprettes et objekt
av klassen CodeFile
, hvor variabler, structer, metoder m.m. kan legges til. N�r alt er
lagt til, kan man hente ut byte-koden med getBytecode()
som
lager en array med bytes (byte[]
). F.eks. se p� dette skallet:
CodeFile codeFile = new CodeFile(); // Her bygges bytekoden opp ... byte[] bytecode = codeFile.getBytecode(); DataOutputStream stream = new DataOutputStream(new FileOutputStream ("Navnet p� filen her ...")); stream.write(bytecode); stream.close();
Bytekoden er stack-basert og har ca. 30 instruksjoner.
Byte-koden er ikke like uttrykkskraftig som spr�ket Db, derfor er reglene for programmene dere skal generere byte-kode for forskjellige fra de dere skal implementere i semantikksjekken. Forskjellen er:
- Det er ikke blokkniv�er. Alts� m� alle strukter v�re deklarert p� det �verste niv�et og det er ikke funksjoner inne i funksjoner.
- Det er ikke referanseparametere, s� basisparameterene overf�rer by-value og struktvariablene er pekerverdier og overf�res ogs� by-value. Alts�, det er p� sammen m�te som i Java.
-
Det er ogs� brukt litt andre navn, slik som at funksjonene kalles prosedyrer
(
Procedure
).
./code-examples/RunMe.d
.
Her er et kort eksempel p� hvordan man bygger opp byte-koden til et enkelt program med en global variabel og en enkel metode med to parametere (float og Complex) og en lokal variabel (int). Metoden printer ut float-parameteren og returnerer. Strukten Complex blir ogs� definert. Legg spesielt merke til at alle deklarasjonene blir definert f�rst og oppdatert senere. Legg ogs� merke til at parameterne f�r nummer fra 0 og oppover og at variabler inne i metoden blir nummerert etter det. Man m� ogs� fortelle den virtuelle maskinen hva som er main-funksjonen. Dette vil alts� v�re kode som for eksempel er spredt rundt i det abstrakte syntakstreet, hvor hver node har ansvar for sine egne instruksjoner.
// Lage example.bin: CodeFile codeFile = new CodeFile(); codeFile.addProcedure("Main"); codeFile.addVariable("myGlobalVar"); codeFile.addProcedure("test"); codeFile.addStruct("Complex"); CodeProcedure main = new CodeProcedure("Main", VoidType.TYPE, codeFile); main.addInstruction(new RETURN()); codeFile.updateProcedure(main); codeFile.updateVariable("myGlobalVar", new RefType(codeFile.structNumber("Complex"))); CodeProcedure test = new CodeProcedure("test", VoidType.TYPE, codeFile); test.addParameter("firstPar", FloatType.TYPE); test.addParameter("secondPar", new RefType(test.structNumber("Complex"))); test.addInstruction(new LOADLOCAL(test.variableNumber("firstPar"))); test.addInstruction(new CALL(test.procedureNumber("print_float"))); test.addInstruction(new RETURN()); codeFile.updateProcedure(test); CodeStruct complex = new CodeStruct("Complex"); complex.addVariable("Real", FloatType.TYPE); complex.addVariable("Imag", FloatType.TYPE); codeFile.updateStruct(complex); codeFile.setMain("Main"); byte[] bytecode = codeFile.getBytecode(); // ... Lagre i filen ./code-examples/example.binResultatet (listingen) av dette blir (Ved � kj�re biten med kode ovenfor og s� kj�re komandoen
java runtime.VirtualMachine -l ./code-examples/example.bin
)
Loading from file: ./code-examples/example.bin Variables: 0: var Complex myGlobalVar Procedures: 0: func void Main() 0: return 1: func void test(float 0, Complex 1) 0: loadlocal 0 1: call print_float {100} 2: return Structs: 0: Complex 0: float 1: float Constants: STARTWITH: Main
Testsuite
Det er laget en patch til det prosjektet som ble delt ut og som dere har bygd p� i oblig 1. Den ligger her og best�r av f�lgende:
-
En ny Compiler-klasse (
.\src\compiler\Compiler.java
). Den inneholder et skall som brukes av testen. Den forutsetter at metodencompile()
returnerer enint
0, 1 eller 2, som nevnt tidligere. -
En hjelpeklasse til testen (
.\src\test\FileEndingFilter.java
). -
Klassen som utf�rer testen (
.\src\test\Tester.java
). -
En katalog med filer det testes mot (
./tests/
). Filene med navn som inneholderfail
skal gi semantikkfeil (2). Ingen av filene skal gi syntaksfeil (1). -
Et testprogram for den virtuelle maskinen (
./code-examples/RunMe.d
). -
Noen linjer som kan legges til build-filen for �
(1) kalle testen (compile-test, test).
(2) kompilere og kj�re eksemplet RunMe (compile-runme, list-runme, run-runme).
De ligger i filen./build.xml.patch
.
Plass�r filene slik katalognavnene er angitt her relativt til banen til
prosjektet deres (Pass p� � legge til
innholdet i Compiler.java
og build.xml
uten � skrive
over de filene dere har).
Etter det kan testen kj�res med
ant test
og dere kan kompilere RunMe med ant compile-runme
og liste ut byte-koden med ant list-runme
.
Klassen Tester kaller klassen Compiler for alle testene i katalogen
./tests/
. Det skrives ut �n linje for hver test, samt en oppsummering.
Sjekkliste for del to
Under f�lger en sjekkliste for semantikken (merk at det kan v�re flere krav, les ogs� spr�knotatet) i Db:
- Multiple deklarasjoner av ett navn i samme skop m� detekteres.
- Typekonvertering: int is-a float, int kan forfremmes til float i aritmetiske uttrykk, returverdier, og som aktuelt argumentuttrykk i funksjonskall.
-
Main-funksjonen
-
Funksjonsdeklarasjonen til
Main
, m� finnes p� �verste blokkniv� av programmet. -
Signaturen m� matche
func Main()
, d.v.s. ingen argumenter og ingen returverdi.
-
Funksjonsdeklarasjonen til
-
Funksjonsdeklarasjoners returverdi er:
- ikke noe, eller
- type i symboltabellen (predefinert eller brukerdefinert struct)
-
Stmts
-
AssignStmt
- Variabelen p� venstresiden m� v�re deklarert.
- Typene p� venstre side og h�yre side m� v�re like, etter evt. typekonvertering.
-
ReturnStmt: Typen til uttrykket skal stemme overens med funksjonens
deklarerte type. Merk ogs� s�rtilfelle uten returverdi,
da blir argumenter til
return
-setningen en feil. -
WhileStmt: m� ha en betingelse av typen
bool
. -
IfStmt: m� ha en betingelse av typen
bool
.
-
AssignStmt
-
Exps
- NewExp: argumentet m� v�re deklarert som en struct-type.
- Literals: M� v�re av en de forh�ndsdefinerte typene i spr�ket: float, int, string, bool eller null.
- Bin�re uttrykk (felles for alle operatorer bortsett fra negasjon) m� ha lik type, etter evt. typeforfremming, p� begge sider av operatoren.
- Aritmetiske uttrykk: som for bin�re uttrykk, men typene m� ogs� begrenses til aritmetiske (int eller float).
- Logiske uttrykk (med "&&", "||" eller "!"): begge operander m� v�re av typen bool.
-
CallStmt
- Navnet som kalles m� v�re deklarert som funksjon.
- Kallet m� ha samme antall aktuelle parametre som formelle parametre.
- De aktuelle parametrene m� ha samme type (eller mulig � tilordne) som de formelle parametrene.
- Bruk av referanser ("ref") m� stemme overens med funksjondeklarasjonen.
-
Var
- Evt. strukt-type m� v�re deklarert.
- Navnet m� v�re deklarert.
Gjennomf�ring og levering
Man leverer sammen med den samme gruppen som man leverte oblig 1. Det som skal leveres er:
- En forside med navn og brukernavn til de som leverer besvarelsen.
- En kort rapport om gjennomf�ringen med forklaring av designet.
-
All kode som trengs for � bygge og kj�re parserne, herunder:
- JFlex-koden for skanneren
- CUP-koden for en av grammatikkene
- Java-koden for syntakstreet, semantikksjekking og byte-kode-generering
- Byggeskript: build.xml eller Makefile
- Instruksjoner for bygging og kj�ring.
- Utskrift fra kj�ring med testesuiten (
ant test
). - Utskrift av listing av byte-koden til eksemplet RunMe.d (
ant list-runme
).
Levering
Besvarelsen leveres som ett pakket filarkiv (zip- eller tgz-format) til gruppel�rer Andreas Svendsen <Andreas.Svendsen@sintef.no>.
Subversion-brukere kan ogs� levere via et repository (bare gi meg leseaksess, og kommandoen for � lese ut prosjektet).
Sist oppdatert 2009-03-24 14:45Andreas Svendsen