Tentamen Imperativ och objektorienterad programmering 2009-12-10 Skrivtid: 0800-1300 Inga hjälpmedel. Tänk på följande Skriv läsligt! Använd inte rödpenna! Skriv bara på framsidan av varje papper. Börja alltid ny uppgift på nytt papper. Lägg uppgifterna i ordning. Skriv uppgiftsnummer och namn på alla papper. Skriv inte längst upp i vänstra hörnet - det går inte att läsa där efter sammanhäftning. Fyll i försättssidan fullständigt. Uppgifterna kommer inte i svårighetsordning. Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren att du har förstått dessa även om detaljer kan vara felaktiga. Programkod skall vara läslig dvs den skall vara vettigt strukturerad och indenterad. Namn på variabler, metoder, funktioner, klasser etc skall vara beskrivande men kan ändå hållas ganska korta. Såvida inget annat anges så får man bygga på lösningar till föregående uppgifter även om dessa inte har lösts. Det är tillåtet att införa hjälpmetoder och hjälpklasser. Uttrycket skriv en metod som skall alltså inte tolkas så att lösningen inte får struktureras med hjälp av flera metoder. Lycka till! 1
Uppgifter 1. Ibland kan det vara fördelaktigt att organisera linjära, länkade listor cirkulärt dvs så att sista elementet pekar till första i stället för NULL. Då kan man låta en lista representeras av en pekare till sista elementet. Detta skulle t ex med fördel kunna ha använts för radnummerlistorna i den första inlämningsuppgiften i C. Det går lätt att lägga till sist och man når ju den första enkelt från den sista t ex för utskrift (eller uttag om det är en kö). I programbilagan listfiles.c finns filer för att implementera detta. Filerna list.h och list.c innehåller det som behövs för att bygga upp och skriva ut cirkulära listor av heltal och listtest.c ett litet testprogram med körresultat. Skriv färdig funktionen listadd körexempel! så att den fungerar enligt specifikation och (3p) 2. I programbilagan treemapfiles.c finns filerna treemap.h och treemap.c som innehåller deklarationer och implementationer för en treemap med strängar som nycklar en godtycklig pekare void * som data. Trädet är organiserat som ett binärt sökträd där mindre nycklar ligger till vänster och större till höger. I programbilagan finns också filen treemaptest som innehåller ett testprogram med körresultat. a) Skriv färdigt funktionen int size(treemap tm) som beräknar och returnerar antalet noder i trädet. (3p) b) Skriv färdigt funktionen put som lagrar ett nyckel-värdepar på rätt plats i trädet i enlighet med specifikationen i koden. (3p) c) Skriv färdigt funktionen containsvalue som returnerar 1 om ett visst värde finns i trädet, annars 0. (3p) d) Det här paketet bygger på att nycklarna är textsträngar (char *). Beskriv vilka ändringar man behöver göra om man vill ha nycklar av en godtycklig typ (dvs void *). Du behöver inte skriva någon kod. (3p) 3. Skriv en main-funktion som läser ord från standard input, lagrar dem tillsammans med en radnummerlista (från uppgift 1 ovan) i ett binärt sökträd (från uppgift 2 ovan). Till din hjälp har du funktionen char *readword() som läser nästa ord från standard input (NULL vid EOF) och funktionen int getlinenumber() som returnerar radnumret för senast levererade ord. Bilagan wordreaderfiles.c innehåller dessa funktioner. Ett exempel på in- och utdata till programmet finns i bilagan data.txt. Tips: Det behövs högst 10 rader (vettigt skriven) kod i funktionen (det räcker med 5 rader förutom main och return men med 8 blir det läsligare) 4. I inlämningsuppgift 5 (kalkylatorn) har ni använt klassen StremTokenizer för att gruppera teckenströmmen från tangentbordet till större enheter såsom tal och ord som sedan hanteras av parsern. Denna klass lämnar ifrån sig dessa enheter via diverse fält (ttype, sval, nval,... ). Ett mer objektorienterat sätt vore att låta tokenizern lämna ifrån sig någon form av tokenobjekt. Eftersom objekten är av olika typ (t ex ord, tal och olika former av specialtecken) så är det lämpligt med en klasshierarki där de olika konkreta klasserna alla är subklasser till en gemensam basklass. Man kan också se till att det finns ett (3p) 2
enhetligt sätt att komma åt textrepresentationen av objekten så att man inte behöver använda sval ibland, ttype ibland och konvertera nval till text ibland. En annan fördel med detta sätt är att användaren av klassen skulle kunna spara tokenströmmen i t ex en lista. Förutom klasshierarkien med olika sorters tokens behövs en klass MyTokenizer som kopplar en indataström till tokenizern och tillhandahåller en metod nexttoken() för att stega fram och några andra metoder som current(), tostring(),... I bilagan TokenizerTest finns kod som exemplifierar användningen. a) Skriv basklassen MyToken samt underklasserna MyWord för ord, MyNumber för tal, MyEOL för radslut, MyEOF för filslut och MyChar för tecken som inte ingår i något av de föregående. Klasserna skall innehålla det data de representerar som attribut samt metoder för att komma åt värdet i textform och, i förekommande fall, talform. (5p) b) I bilagan MyTokenizer.java finns klassen MyTokenizer påbörjad. Den använder den inbyggda klassen StreamTokenizer för att gruppera teckenströmmen. Skriv färdig metoden nexttoken()! (3p) 5. I bilagor till skrivningen finns ett program som läser och evaluerar uttryck på samma sätt som inlämningsuppgift 5. Bilagan Parser.java innehåller parser-metoder samt main-metoden, bilagan Klasshierarki.java innehåller klasserna som definierar de olika nodtyperna i den interna representationen och bilagan Symbolic.java innehåller metoder för symbolisk/numerisk aritmetik. Vissa delar av koden är utelämnade. Av utrymmeskäl är också alla import- och package-satser borttagna. Till skillnad från inlämningsuppgiften så hanteras (utförs) kommandon (quit och variables) av parsern och utskrifter av metoden statement(). Dessutom är, av utrymmesskäl, hantering av funktionerna sin och cos utelämnade. Programmet kan även hantera absolutbelopp som framgår av körexemplen:? 2*(3=a=b)=c Read : 2.0*(3.0=a=b)=c Evaluated : 6.0? variables Variables: {a=3.0, b=3.0, c=6.0? a Read : a Evaluated : 3.0? x + y = z Read : x+y=z Evaluated : x+y? z Read : z Evaluated : x+y? 1=x Read : 1.0=x Evaluated : 1.0? 2=y Read : 2.0=y Evaluated : 2.0? x+y=z Read : x+y=z Evaluated : 3.0 3
? variables Variables: {a=3.0, b=3.0, c=6.0, x=1.0, y=2.0, z=3.0? a-2*b = c Read : a-2.0*b=c Evaluated : -3.0? c Read : c Evaluated : -3.0? c = c Read : c =c Evaluated : 3.0? -2=x Read : - 2.0=x Evaluated : -2.0? x - 2* y = z Read : x -2.0* y =z Evaluated : 2.0? variables Variables: {a=3.0, b=3.0, c=3.0, x=-2.0, y=2.0, z=2.0? " x -4* y = b = z Read : "( x -4.0* y =b )=z Evaluated : x -4.0* y =b? variables Variables: {a=0.0, b=3.0, c=3.0, x=-2.0, y=2.0, z= x -4.0* y =b? z Read : z Evaluated : x -4.0* y =b? &z Read : & z Evaluated : 6.0? variables Variables: {a=0.0, b=-6.0, c=3.0, x=-2.0, y=2.0, z= x -4.0* y =b? z x Read : z x *** Eval Error: Can not differentiate:? "(x=y) x Read : "(x=y) x *** Eval Error: Can not differentiate: =? quit a) Skriv assignment-metoden i klassen Parser som parsar tilldelningsuttryck (assignment) enligt samma syntax som i inlämningsuppgift 5. Se körexemplen! (4p) b) Skriv färdigt eval-metoden i klasserna Assignment så att de fungerar som i körexemplen (och inlämningsuppgiften). (4p) c) Komplettera parsern så att den kan hantera absolutbeloppsoperatorn. Denna operator skrivs så att den omger sin operand med vertikalstreck ( ). Se körexempel! Parsern skall skapa objekt av typen Positive för absultbeloppsuttryck. Implementera också klassen Positive och och metoden positive i Symbolic som hanterar absolutbelopp så att funktionen blir enligt körexemplen. Absolutbeloppsoperatorn är inte deriverbar. Tips: Syntaktiskt har denna operator vissa likheter med parentesuttryck. (6p) 4
Dec 10, 09 9:22 Page 1/1 /* list.h Listor med heltal typedef struct listnode { int line; struct listnode *next; listnode, *List; List listadd(list l, int line); // Ny nod sist void listprint(list l); // Skriver ut listan /* /* list.c Implementationsfil för heltalslistor #include <stdio.h> #include <stdlib.h> #include "list.h" * Skapar och lägger in en ny nod sist i listan * Precondition: l pekar till sista noden eller NULL * Returnerar : pekare till den nya sista noden * Invariant : Sista nodens next pekar till första noden List listadd(list l, int line) { List node = (List) malloc(sizeof(listnode)); //... *** Uppgift 1 void listprint(list l) { printf("["); if ( l!=null) { List t = l >next; // Börja med första elementet do { printf("%d ", t >line); t = t >next; while (t!=l >next); // Så länge sista elementet inte nåtts printf("]"); /* /* listtest.c #include <stdio.h> #include "list.h" int main() { List l = NULL; l = listadd(l, 2); l = listadd(l, 7); l = listadd(l, 17); l = listadd(l, 42); listprint(l); printf("\n"); listfiles.c Dec 10, 09 9:23 Page 1/3 /* treemap.h typedef struct treenode { char *key; void *data; struct treenode *left; struct treenode *right; treenode, *link; typedef link TreeMap; // Avsedd för externt bruk Konstruktor TreeMap newtreemap(); Lagrar paret (nyckel, data) i trädet tm. * Om nyckeln inte finns i trädet så skapas en ny nod (nyckel,data) * annars ändras värdet för den lagrade nyckeln. * Returnerar pekare till roten i det modifierade (del )trädet. link put (TreeMap tm, char *key, void *data); Returnerar det som är lagrat med nyckeln key eller NULL om key * inte finns i trädet void *get (TreeMap tm, char *key); Returnerar ett värde!= 0 om key finns i trädet, annars 0 int containskey (TreeMap tm, char *key); Returnerar ett värde!= 0 om någon nod i trädet har ett datafält * som är lika med val. * equals är en funktion som avgör vad som menas med lika. int containsvalue(treemap tm, void *val, int equals(void *, void *)); Skriver ut noderna i trädet. * data delen skrivs ut genom anrop till funktionen prt void print (TreeMap tm, void prt(void *)); Returnerar antalet noder i trädet int size (TreeMap tm); treemapfiles.c /* Output: [2 7 17 42 ] Thursday December 10, 2009 listfiles.c, treemapfiles.c 1/10
Dec 10, 09 9:23 Page 2/3 /* /* treemap.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include "treemap.h" TreeMap newtreemap() { return NULL; link newtreenode(char *key, void *data) { link n = (link) malloc(sizeof(treenode)); n >key = key; n >data = data; n >left = n >right = NULL; return n; int size(treemap r) { //... *** Uppgift 2a int containskey(treemap r, char *key) { //... Behöver ej skrivas link put(treemap r, char *key, void *data) { //... *** Uppgift 2b void *get(treemap r, char *key) { if (r==null) return NULL; if ( strcmp(key, r >key) < 0 ) return get(r >left, key); if ( strcmp(key, r >key) > 0 ) return get(r >right, key); return r >data; int containsvalue(treemap r, void *data, int equals(void *, void *)) { //... *** Uppgift 2c void print(treemap r, void prt(void *)) { if (r) { print(r >left, prt); printf("%10s : ", r >key); prt(r >data); printf("\n"); print(r >right, prt); treemapfiles.c Dec 10, 09 9:23 Page 3/3 /* /* treemaptest.c #include <stdio.h> #include "treemap.h" int equals(void *x, void *y) { // För jämför av datadelen return (int)x == (int) y; void prt(void *data) { // För utskrift av testdata printf(" %d", (int)data); int main() { TreeMap tm = newtreemap(); tm = put(tm, "x", (void *)1); // Ett brutalt och aningen tm = put(tm, "y", (void *)2); // riskabelt sätt men tm = put(tm, "z", (void *)3); // duger för enkel testning tm = put(tm, "a", (void *)4); // och demonstration tm = put(tm, "z", (void *)5); if (containskey(tm, "z")) { printf("ja, z finns med värdet: %d\n", (int) get(tm, "z")); if (containsvalue(tm, (void *)17, equals)) { printf("ja, 17 finns\n"); { printf("nej, 17 finns inte\n"); if (containsvalue(tm, (void *)5, equals)) { printf("ja, 5 finns\n"); { printf("nej, 5 finns inte\n"); printf("\nträdet har %d noder och innehåller följande (i ordning):\n", size(tm)); print(tm, prt); return 0; /* Output: ja, z finns med värdet: 5 nej, 17 finns inte ja, 5 finns treemapfiles.c Trädet har 4 noder och innehåller följande (i ordning): a : 4 x : 1 y : 2 z : 5 Thursday December 10, 2009 treemapfiles.c 2/10
Dec 10, 09 9:23 Page 1/1 /* wordreader.h char *readword(); // Returnerar nästa ord int getlinenumber(); // Returnerar aktuellt radnummer /* /* wordreader.c #include <stdio.h> #include <ctype.h> #include <string.h> #include "wordreader.h" static int linenumber = 1; * Returnerar nästa ord (obruten sekvens av bokstäver) från * standard input char *readword() { char buffer[1000]; int i; int c= getchar(); while (!isalpha(c)) { // Hitta första bokstav if (c==eof) return NULL; if (c== \n ) linenumber++; c = getchar(); wordreaderfiles.c i = 0; while (isalpha(c)) { // samla bokstäver buffer[i++] = c; c = getchar(); buffer[i] = \0 ; ungetc(c, stdin); // Lägg tillbaka "icke bokstaven" return strdup(buffer); // Kopiera till lagom stor area Dec 10, 09 9:24 Page 1/1 Indata: Den mätta dagen, den är aldrig störst. Den bästa dagen är en dag av törst. Nog finns det mål och mening i vår färd men det är vägen, som är mödan värd. Utdata: Den : [1 2 ] Nog : [4 ] aldrig : [1 ] av : [2 ] bästa : [2 ] dag : [2 ] dagen : [1 2 ] den : [1 ] det : [4 5 ] en : [2 ] finns : [4 ] färd : [4 ] i : [4 ] men : [5 ] mening : [4 ] mätta : [1 ] mål : [4 ] mödan : [5 ] och : [4 ] som : [5 ] störst : [1 ] törst : [2 ] vägen : [5 ] värd : [5 ] vår : [4 ] är : [1 2 5 5 ] data.txt * Returnerar aktuellt radnummer int getlinenumber() { return linenumber; Thursday December 10, 2009 wordreaderfiles.c, data.txt 3/10
Dec 10, 09 9:25 Page 1/1 * Testprogram för MyTokenizer import mytokenizer.*; import java.io.ioexception; public class TokenizerTest { TokenizerTest.java public static void main(string[] args) throws IOException { MyTokenizer mt = new MyTokenizer(); MyToken t; System.out.println("End with quit or EOF"); System.out.print("> "); do { t = mt.nexttoken(); System.out.println(t.toString() + " \t: " + mt.tostring()); try { // Prova något eventuellt illegalt if (t.isnumber() t.isword() ) { double nbr = t.getnumber(); catch (MyToken.MyTokenException me) { System.out.println("*** Error *** " + me.getmessage() + ": " + t); System.out.println("*** occured after: " + mt.previous()); if (t.iseol()) { // Ny prompter vid radslut System.out.println("End with quit or EOF"); System.out.print("> "); while (!t.iseof() &&!t.tostring().equals("quit")); /* Testkörning: rontok$ java TokenizerTest End with quit or EOF > 123+567=x+18 123.0 : class mytokenizer.mynumber[123.0] on line 1 + : class mytokenizer.mychar[+] on line 1 567.0 : class mytokenizer.mynumber[567.0] on line 1 = : class mytokenizer.mychar[=] on line 1 x : class mytokenizer.myword[x] on line 1 *** Error *** getnumber called for a nonnumber: x *** occured after: = + : class mytokenizer.mychar[+] on line 1 18.0 : class mytokenizer.mynumber[18.0] on line 1 *EOL* : class mytokenizer.myeol[*eol*] on line 2 End with quit or EOF > ()(2) ( : class mytokenizer.mychar[(] on line 2 ) : class mytokenizer.mychar[)] on line 2 ( : class mytokenizer.mychar[(] on line 2 2.0 : class mytokenizer.mynumber[2.0] on line 2 ) : class mytokenizer.mychar[)] on line 2 *EOL* : class mytokenizer.myeol[*eol*] on line 3 End with quit or EOF > quit quit : class mytokenizer.myword[quit] on line 3 *** Error *** getnumber called for a nonnumber: quit *** occured after: *EOL* rontok$ Dec 10, 09 9:27 Page 1/1 package mytokenizer; import java.io.*; A tokenizer for standard input. A token is one of the following subclasses to MyToken: MyNumber a number (digits, possibly with decimals) MyWord a word (a sequence of letters) MyEOL an eol MyEOF an eof MyChar a char i.e any nonspace character not forming the above tokens The tokenizer keeps track of the current and the previous token. public class MyTokenizer { private StreamTokenizer st = new StreamTokenizer( new BufferedReader( new InputStreamReader(System.in)));; private MyToken current; private MyToken previous; public MyTokenizer() throws IOException { st.eolissignificant(true); st.ordinarychar( + ); st.ordinarychar( ); previous = current = new MyWord("*BOF*"); //"Beginning Of File" public String tostring() { return current.getclass() +"[" + current + "] on line " + st.lineno(); * Advances to next token * @return next token (i e the new current token) public MyToken nexttoken() throws IOException { //... *** Uppgift 4 * @return current token public MyToken current() { return current; * @return the previous current token public MyToken previous() { return previous; MyTokenizerFiles.java * @return the line number for the current token public int lineno() { return st.lineno(); Thursday December 10, 2009 TokenizerTest.java, MyTokenizerFiles.java 4/10
Dec 10, 09 9:28 Page 1/4 /* Symbolisk kalkylator Förvillkor för alla parser metoder förutom main, run: Tokenizern positionerad till det första obehandlade token dvs till det token som står på tur att behandlas. Eftervillkor för alla parser metoder utom main, run och statement: Tokenizern positionerad till det första obehandlade token. import java.util.*; import java.io.*; import symbolic.*; public class Parser { private StreamTokenizer st; private TreeMap<String, Sexpr> map; private HashSet<String> commands; private HashSet<String> unaries; Parser.java public class SyntaxException extends RuntimeException { public SyntaxException(String msg) { super(msg); public static void main(string [] args) throws IOException { Parser p = new Parser(); p.run(); public Parser() throws IOException { st = new StreamTokenizer( new BufferedReader( new InputStreamReader(System.in))); st.eolissignificant(true); st.ordinarychar( + ); st.ordinarychar( ); st.ordinarychar( / ); st.ordinarychar( * ); st.ordinarychar( ); st.ordinarychar( \ ); st.ordinarychar( " ); {char c= " ; // To fool a2ps st.ordinarychar( & ); Parser.java Dec 10, 09 9:28 Page 2/4 System.out.print("? "); while ( st.nexttoken() == StreamTokenizer.TT_EOL ); statement(); catch (SyntaxException e) { System.out.println("* Syntax Error: " + e.getmessage()); while ( st.ttype!= StreamTokenizer.TT_EOL ) catch (EvaluationException e) { System.out.println("*** Eval Error: " + e.getmessage()); public void statement() throws IOException { if ( st.ttype==streamtokenizer.tt_word && commands.contains(st.sval) ) { command(); { Sexpr d = assignment(); System.out.println("Read : " + d); Sexpr v = d.eval(map); map.put("ans", v); System.out.println("Evaluated : " + v); if ( st.ttype!= StreamTokenizer.TT_EOL ) throw new SyntaxException("Expected EOL but found: " + st); public void command() throws IOException { if (st.sval.equals("quit") ) { System.out.println("Bye"); System.exit(0); if ( st.sval.equals("variables") ) { System.out.println("Variables: " + map); if (st.sval.equals("clear")) { while (st.ttype==streamtokenizer.tt_word) { map.remove(st.sval); if ( st.ttype!=streamtokenizer.tt_eol) throw new SyntaxException("Expected EOL but found: " + st); throw new SyntaxException("Unknown command: " + st); map = new TreeMap<String,Sexpr>(); unaries = new HashSet<String>(); commands = new HashSet<String>(); unaries.add(" "); unaries.add("exp"); unaries.add("log"); unaries.add("\""); unaries.add("&"); commands.add("quit"); commands.add("variables"); commands.add("clear"); public Sexpr assignment() throws IOException { //... *** Uppgift 5 a public Sexpr expression() throws IOException { Sexpr sum = term(); while ( st.ttype == + st.ttype == ) { int oper = st.ttype; if (oper== + ) sum = new Addition(sum, term()); sum = new Subtraction(sum, term()); public void run() throws IOException { while (true) try { do { return sum; Thursday December 10, 2009 Parser.java 5/10
Parser.java Dec 10, 09 9:28 Page 3/4 public Sexpr term() throws IOException { Sexpr prod = factor(); while ( st.ttype == * st.ttype == / ) { int oper = st.ttype; if ( oper == * ) prod = new Multiplication(prod, factor()); prod = new Division(prod, factor()); return prod; Parser.java Dec 10, 09 9:28 Page 4/4 return new Evaluation(primary()); if (op.equals("exp")) return new Exp(primary()); if (op.equals("log")) return new Log(primary()); throw new SyntaxException("Undefined operator: " + op); public Sexpr factor() throws IOException { Sexpr result = primary(); while ( st.ttype == \ ) { if ( st.ttype!= StreamTokenizer.TT_WORD ) throw new SyntaxException("Expected identifier but found: " + st); { result = new Differentiation(result, new Variable(st.sval)); return result; public Sexpr primary() throws IOException { Sexpr result = null; if ( st.ttype == ( ) { // ( assignment ) result = assignment(); if ( st.ttype!= ) ) throw new SyntaxException("Expected ) but found " + st); if ( st.ttype == StreamTokenizer.TT_NUMBER ) { // number result = new Constant(st.nval); { String op = "" + (char) st.ttype; if ( st.ttype == StreamTokenizer.TT_WORD ) op = st.sval; if ( unaries.contains(op) ) { // unary result = unary(op); if ( st.ttype == StreamTokenizer.TT_WORD ) { // identifier result = new Variable(op); { // error throw new SyntaxException("Unexpected: " + st); return result; public Sexpr unary(string op) throws IOException { if (op.equals(" ")) return new Negation(primary()); if (op.equals("\"")) return new Quotation(primary()); if (op.equals("&")) Thursday December 10, 2009 Parser.java 6/10
Dec 10, 09 9:29 Page 1/6 // class Addition public class Addition extends Binary { public Addition(Sexpr left, Sexpr right) { super(left, right); return Symbolic.add( left.eval(map), right.eval(map)); return "+"; return Symbolic.add(left.diff(x), right.diff(x)); return 10; // class Assignment public class Assignment extends Binary { //... *** Uppgift 5 b // class Atom public abstract class Atom extends Sexpr { public String tostring() { return getname(); // class Binary public abstract class Binary extends Sexpr { protected final Sexpr left, right; public Binary(Sexpr left, Sexpr right) { this.left = left; this.right = right; return 30; // Default for *, / public String tostring() { //... behöver inte skrivas // class Constant public class Constant extends Atom { private final double value; public Constant(double value) { this.value = value; Klasshieararki.java Dec 10, 09 9:29 Page 2/6 return this; return "" + value; return new Constant(0); public double getvalue() { return value; public boolean isconstant() { return true; public isconstant(double value) { return value==this.value; // class Differentiation public class Differentiation extends Binary { public Differentiation(Sexpr left, Sexpr right) { super(left, right); Sexpr val = left.eval(map); return val.diff(right); return " "; return 40; // class Division public class Division extends Binary { public Division(Sexpr left, Sexpr right) { super(left, right); return Symbolic.divide(left.eval(map), right.eval(map)); return "/"; Klasshieararki.java Thursday December 10, 2009 Klasshieararki.java 7/10
Dec 10, 09 9:29 Page 3/6 Sexpr numerator = Symbolic.subtract( Symbolic.multiply(left.diff(x), right), Symbolic.multiply(left, right.diff(x)) ); Sexpr denominator = Symbolic.multiply(right, right); return Symbolic.divide(numerator, denominator); return 30; // class Evaluation public class Evaluation extends Unary { public Evaluation(Sexpr argument) { super(argument); return argument.eval(map).eval(map); return "&"; // class EvaluationException public class EvaluationException extends RuntimeException { Klasshieararki.java public EvaluationException(String msg) { super(msg); // class Exp public class Exp extends Unary { public Log(Sexpr argument) { super(argument); return Symbolic.log(argument.eval(map)); return "log"; return Symbolic.divide(argument.diff(x), x); // class Multiplication public class Multiplication extends Binary { Dec 10, 09 9:29 Klasshieararki.java Page 4/6 public Multiplication(Sexpr left, Sexpr right) { super(left, right); return Symbolic.multiply( left.eval(map), right.eval(map)); return "*"; return Symbolic.add( Symbolic.multiply(left.diff(x), right), Symbolic.multiply(left, right.diff(x)) ); return 30; public Exp(Sexpr argument) { super(argument); return Symbolic.exp(argument.eval(map)); return "exp"; return Symbolic.multiply(argument.diff(x), new Exp(x)); // class Log public class Log extends Unary { // class Negation public class Negation extends Unary { public Negation(Sexpr argument) { super(argument); return Symbolic.negate(argument.eval(map)); return " "; return Symbolic.negate(argument.diff(x)); Thursday December 10, 2009 Klasshieararki.java 8/10
// class Quotation public class Quotation extends Unary { Dec 10, 09 9:29 Klasshieararki.java Page 5/6 public Quotation(Sexpr argument) { super(argument); return argument; return "\""; // class Sexpr public abstract class Sexpr { public abstract Sexpr eval(map<string, Sexpr> map); public abstract String getname(); Dec 10, 09 9:29 Page 6/6 return Symbolic.subtract(left.diff(x), right.diff(x)); return 10; // class Unary public abstract class Unary extends Sexpr { protected final Sexpr argument; public Unary(Sexpr argument) { this.argument = argument; return 50; Klasshieararki.java throw new EvaluationException("Can not differentiate: " + getname()); public double getvalue() { throw new RuntimeException("Internal error: getvalue()"); public String tostring() { if ( argument.priority() <= priority() ) return getname() + "(" + argument.tostring() + ")"; return getname() + " " + argument.tostring(); return 100; public boolean isconstant() { return false; // class Variable public class Variable extends Atom { private final String ident; public Variable(String ident) { this.ident = ident; public boolean isconstant(double v) { return false; public boolean equals(sexpr e) { return tostring().equals(e.tostring()); // class Subtraction public class Subtraction extends Binary { public Subtraction(Sexpr left, Sexpr right) { super(left, right); return Symbolic.subtract( left.eval(map), right.eval(map)); return " "; if ( map.containskey(ident) ) return map.get(ident); return this; return ident; if (ident.equals(x.getname())) return new Constant(1.); return new Constant(0.); Thursday December 10, 2009 Klasshieararki.java 9/10
Dec 10, 09 9:29 Page 1/2 package symbolic; public class Symbolic { public static Sexpr add(sexpr a, Sexpr b) { if ( a.isconstant() && b.isconstant() ) return new Constant(a.getValue() + b.getvalue()); if ( a.isconstant(0.) ) return b; if ( b.isconstant(0.) ) return a; if ( a.equals(b) ) return new Multiplication(new Constant(2.), a); return new Addition(a, b); Symbolic.java public static Sexpr multiply(sexpr a, Sexpr b) { if ( a.isconstant() && b.isconstant() ) return new Constant(a.getValue() * b.getvalue()); if ( a.isconstant(0.) b.isconstant(0.) ) return new Constant(0); if ( a.isconstant(1.) ) return b; if ( b.isconstant(1.) ) return a; return new Multiplication(a, b); Dec 10, 09 9:29 Page 2/2 if ( x.isconstant() ) return new Constant( Math.log(x.getValue()) ); return new Log(x); public static Sexpr negate(sexpr x) { if ( x.isconstant() ) return new Constant( x.getvalue()); return new Negation(x); Symbolic.java public static Sexpr positive(sexpr x) { if (x.isconstant()) return new Constant(Math.abs(x.getValue())); return new Positive(x); public static Sexpr subtract(sexpr a, Sexpr b) { if ( a.isconstant() && b.isconstant() ) return new Constant(a.getValue() b.getvalue()); if ( b.isconstant(0.) ) return a; if ( a.equals(b) ) return new Constant(0); return new Subtraction(a, b); public static Sexpr divide(sexpr a, Sexpr b) { if ( a.isconstant() && b.isconstant() ) return new Constant(a.getValue() / b.getvalue()); if ( a.isconstant(0.) ) return new Constant(0.); if ( b.isconstant(1.) ) return a; if ( a.equals(b) ) return new Constant(1.); return new Division(a, b); public static Sexpr exp(sexpr x) { if ( x.isconstant() ) return new Constant( Math.exp(x.getValue()) ); return new Exp(x); public static Sexpr log(sexpr x) { Thursday December 10, 2009 Symbolic.java 10/10