FACIT TILL TENTAMEN I PROGRAMSPRÅK DVG C01 140605 kl. 08:15-13:15 Ansvarig Lärare: Donald F. Ross Hjälpmedel: Bilaga A: BNF-definition Betygsgräns: Kurs: Max 60p, Med beröm godkänd 50p, Icke utan beröm godkänd 40p, Godkänd 30p (varav minimum 20p från tentan, 10p från labbarna) Tenta: Max 40p, Med beröm godkänd 34p, Icke utan beröm godkänd 27p, Godkänd 20p Labbarna: Max 20p, Med beröm godkänd 18p, Icke utan beröm godkänd 14p, Godkänd 10p SKRIV TYDLIGT LÄS UPPGIFTERNA NOGGRANT 1. Ange kortfattade svar på följande uppgifter: 1. Ge en definition av (i) aktuell parameter samt (ii) formell parameter (i) Expression (ii) Identifier 2. Vad är skillnaden mellan den lokala omgivningen (engelska: local environment) och den icke-lokala omgivningen (engelska: non-local environment)? The local environment is the function/program in which expressions are evaluated The non-local environment is the surrounding environment which may be deretmined in 2 ways (i) statically: the lexically enclosing environment (ii) dynamically by the call sequence for functions. 3. Vad betyder G = (S, P, NT, T)? The definition of a grammar for a language, denoted L(G). S is the start symbol (a non-terminal symbol) P is a set (sequence) of production rules with a single non-terminal on the LHS and a string of terminal and non-terminal symbols on the RHS NT is the set of non-terminal symbols T is the set of terminal symbols 4. Vad är förhållandet mellan ett lexem och en token? A lexeme is a substring of the input string (in this context a program written in a given programming language) and a token defines a class (or category) of lexemes. Often there is only one lexeme in the token class (e.g. lexeme program and token PROGRAM) but in the case if identifiers and numbers there can be a potentially infinite number (e.g. lexemes a, b, c are all in the token class ID) DFR/AA/ND 140605 PS tentamen facit Sidan 1 av 15
5. Vad är skillnaden mellan en derivation (engelska: derivation) och en parsning (engelska: parse)? Derivation: start with S the start symbol and using the rules in P show that the final string of terminal symbols (w) (a sentence in the grammar) can be produced (derived) in a series of steps Parsing: start with the sentence (w) and show that the sentence can (a) be derived from S (top down parsing (RDPP) is a controlled derivation using each input symbol to decide the next grammar rule to apply or (b) in bottom-up parsing that w can be reduced to S using the grammar rules in P. 6. I en RDPP (engelska: Recursive Descent Predictive Parser) vad innebär Predictive? Ge ett exempel för att förklara denna aspekt. That the incoming terminal symbol (lookahead) can be used to determine which grammar rule from P to apply next. For example if the grammar has assignment, a while statement and an if statement then the code in statement() might be Void statement () { if (lookahead == ID) assign_statement(); else if (lookahead == IF) if_statement(); else if (lookahead == WHILE) while_statement(); else error( Unexpected symbol in statement ); 7. Vad är ett reguljäruttryck (engelska: regular expression)? Ge ett exempel. A literal string e.g. program or an rule giving how a string may be matched e.g. for an identifier which should begin with a letter and may have any number of alphamumeric characters, a definition might be [A-Za-z][ A-Za-z0-9]* 8. Vad är skillnaden mellan syntax och semantiken? Syntax: that which is defined by the grammar as defined by G = (S, P, NT, T) Semantics: the meaning of the constructions defined by the grammar (all else other than the syntax) e.g. if identifiers are doubly defined or not defined at all 9. Ge ett exempel av en typkonstruktor (engelska: type constructor). Array, struct, pointer 10. Vad betyder uttrycket referential transparency? In a program, if an expression can be replace with its value without changing the result of the program. Mathematical functions possess this proporty hence the advanyage of functional programming. Functions in programming language may not possess this property, i.e. a function may have side effects. Totalt 5p DFR/AA/ND 140605 PS tentamen facit Sidan 2 av 15
2. Symboltabell Vad är förhållandet mellan symboltabellen och den exekvering-tids omgivning (engelska: run-time environment)? Ge gärna exempel i Ditt svar. Vilka eventuella organisationer finns för en symboltabell? The symbol table is essentially a descriptor for the activation record (in the static area or the stack) and contains information about the size of the activation record and the size and position of each data object together with the type which tells the system how to interpret the byte sequence. Organisations: table (sequence) or tree structured Marks for good example(s) and explanation(s) Points for discussion 1. Content of the symbol table and its meaning 2. How is scope (lexical) represented? 3. Relationship of the symbol table to the run-time stack 4. How is the current scope defined at run-time? 5. Organisation as a table 6. Organisation as a tree (for languages with procedures and nested procedures) o What does this mean with regard to scope and local/non-local environments 5p DFR/AA/ND 140605 PS tentamen facit Sidan 3 av 15
3. Felhantering och återhämting Titta på programmet nedan och resultatet från en parsning. program testp (input, output); var A, B, C: integer; A := B + C * 2 end. $ SEMANTIC: ID already declared: A --message 1 SYNTAX: Symbol expected : found := --message 2 SYNTAX: Type name expected found := --message 3 SYNTAX: Symbol expected ; found := --message 4 SYNTAX: Symbol expected begin found := --message 5 SYNTAX: ID expected found := --message 6 SEMANTIC: Assign types: error := integer --message 7 Med hjälp av grammatiken i Bilaga A förklara vad har hänt under parsningen. Ge en trace (spår) av parsningsprocessen för just detta program. 3p The problem here is that the parser is in var_part() and has just processed a var_dec ( A, B, C: integer ). There are 2 possibilities (i) the programmer has written a second var_dec, which begins with an ID or (ii) the var_dec was the last (here only) var_dec in the var_dec_list and the next symbol should be begin which signifies the beginning of the stat_part. Here the actual error is that the begin is missing and the lookahead symbol is an ID (A). The resulting action now depends on how the programmer wrote the parser! One standard way is to continue processing var_decs when an ID is found, which is what the programmer here has done. Unfortunately A has already been declared (message 1 from id_list()). Since the A has been read, lookahead is now := (assign). However the parser is still in var_dec_list() which has called var_dec() again which has called id_list(). If id_list() finds a comma it continues processing the id_list however lookahead is assign hence id_list() returns to var_dec() which is now expecting a colon (message 2). Then var_dec() expects a type (message 3). Var_dec() then expects a semicolon (message 4). Var_dec does not find another ID (lookahead is assign) and hence exits. The parser then calls stat_part() which expects a begin (message 5). Stat_part() then calls stat_list() which calls stat() which calls assign_stat(). Assign_stat() now expects an ID (message 6). Assign_stat() now expects an assign and finds this so that the parse tree and input stream are now resynchronised. The expression is processed without problem (B + C * 2) and assign_stat() perfoms a type check on the LHS and RHS of the assignment. A was processed by var_dec() hence assign_stat() has interpreted the LHS of the assignment as an error (message 7). Note that the expression on the RHS has been correctly parsed and its type determined. DFR/AA/ND 140605 PS tentamen facit Sidan 4 av 15
The trace for the program is:- 1. *** In program_header 2. *** In match expected program found program 3. *** In match expected id found testp 4. *** In match expected ( found ( 5. *** In match expected input found input 6. *** In match expected, found, 7. *** In match expected output found output 8. *** In match expected ) found ) 9. *** In match expected ; found ; 10. *** In var_part 11. *** In match expected var found var 12. *** In var_dec_list 13. *** In var_dec 14. *** In id_list 15. *** In match expected id found A 16. *** In match expected, found, 17. *** In id_list 18. *** In match expected id found B 19. *** In match expected, found, 20. *** In id_list 21. *** In match expected id found C 22. *** In match expected : found : 23. *** In type 24. *** In match expected integer found integer 25. *** In match expected ; found ; 26. *** In var_dec 27. *** In id_list 28. *** In match expected id found A 29. SEMANTIC: ID already declared: A 30. *** In match 31. SYNTAX: Symbol expected : found := 32. *** In type 33. SYNTAX: Type name expected found := 34. *** In match 35. SYNTAX: Symbol expected ; found := 36. *** In stat_part 37. *** In match 38. SYNTAX: Symbol expected begin found := 39. *** In stat_list 40. *** In stat 41. *** In assign_stat 42. SYNTAX: ID expected found := 43. *** In match expected := found := resync! 44. *** In expr 45. *** In term 46. *** In factor 47. *** In match expected id found B DFR/AA/ND 140605 PS tentamen facit Sidan 5 av 15
48. *** In R2 49. *** In R1 50. *** In match expected + found + 51. *** In term 52. *** In factor 53. *** In match expected id found C 54. *** In R2 55. *** In match expected * found * 56. *** In factor 57. *** In match expected number found 2 58. *** In R2 59. *** In R1 60. SEMANTIC: Assign types: error := integer 61. *** In match expected end found end 62. *** In match expected. found. Föreslå eventuella lösningar för att kunna få en bättre återhämtning än den som togs ovan. Possible solutions 2p 1. Optimal Solution: Require each var_dec to begin ith the keyword var the problem would then be resolved since the parser will move to stat_part and find A and write Symbol expected begin found A. A is then found by the next step in assign_stat and the parser is resynchronised. 2. 2 symbol lookahead instead of 1 symbol lookahead this would find the ID (A) and the assign ( := ). Var_dec() could then exit without giving messages 1-4. Stat_part() would still give an error message ( begin expected found ID ) and would resynchronise in assign_stat() on the ID 3. Since A is found to be already declared, the programmer could assume that the begin is missing, terminate var_dec() and pass control to stat_part() which would detect the missing begin but then resynchronise in asign_stat(). 4. A check could be made for := which occurs only in stat_part. Error signalling could be switched off until stat_part() is called (line 36) which would suppress error messages 2, 3 and 4 giving:- SEMANTIC: ID already declared: A --message 1 SYNTAX: Symbol expected begin found := --message 5 SYNTAX: ID expected found := --message 6 SEMANTIC: Assign types: error := integer --message 7 Totalt 5p DFR/AA/ND 140605 PS tentamen facit Sidan 6 av 15
4. Typer Diskutera ingående de olika aspekterna av typer i programspråk. 5p Marks for good answers. Points for discussion See Sebesta Chapter 6 on types 1. What is a type? 2. Type values (domain) & associated operations. 3. Atomic types: integer, real, Boolean, character, (Lisp ratio) 4. Strong and weak typing. 5. Type checking. 6. Type equivalence. 7. Explicit and implicit strong typing (type inference). 8. Advantages and disadvantages of typing. 9. Type casting (explicit) and coercion (implicit). 10. How do types relate to data objects (variables)? 11. What are type constructors? Give examples. a. Array types properties. b. Structure (record) types. c. String types. d. Pointer & reference types. e. Union types 12. What are type operations? 13. What are the operations associated with a type and its instances (data objects)? 14. Can types be passed as parameters? 15. Types and variables (instances of types) 16. How are types used at run-time? 17. Types as (self) documentation. 18. Types versus OO classes. 19. Type predicates in weakly typed languages. 5. Parametrar Diskutera ingående hur parametrar hanteras vid exekverings-tid (engelska: run-time environment). Marks for good answers. See the revision notes on the web. 5p DFR/AA/ND 140605 PS tentamen facit Sidan 7 av 15
6. Lisp Vad är resultatet på varje print operation i följande kod i Lisp? (setf q (last (cons '(A B) (append (list '(A B) '(A B)) '(A B)) ) ) ) (print q) (setf q (remove-if-not #'listp (cons '(A B) (append (list '(A B) '(A B)) '(A B)) ))) (print q) Work out from the inside out by stages 1p 1. (list '(A B) '(A B)) ( (A B) (A B) ) 2. (append ( (A B) (A B) ) '(A B)) ( (A B) (A B) A B) 3. (cons '(A B) ( (A B) (A B) A B) ) ( (A B) (A B) (A B) A B) 4. (last ( (A B) (A B) (A B) A B) ) (B) 5. q is (B) 1. (list '(A B) '(A B)) ( (A B) (A B) ) 2. (append ( (A B) (A B) ) '(A B)) ( (A B) (A B) A B) 3. (cons '(A B) ( (A B) (A B) A B) ) ( (A B) (A B) (A B) A B) 4. (remove-if-not #'listp ((A B) (A B) (A B) A B)) ( (A B) (A B) (A B) ) 5. q is ( (A B) (A B) (A B) ) Answers Overview 1. q is (B) 2. q is ( (A B) (A B) (A B) ) 3. q is ( B B ) 4. q is (12 14 16 18) 5. b is ((A (A B)) (B (C D)) (C (E F))) 6. q is ((A (A B)) (S ((C D) B)) (C (E F))) + explanation of procedure q. DFR/AA/ND 140605 PS tentamen facit Sidan 8 av 15
(setf x 'A) (let* ((x 'B) (y x)) (setf q (list x y)) (print q) ) (setf q (mapcar #'(lambda (n) (* (+ n 1) 2)) '(5 6 7 8))) (print q) These expressions should be worked through sequentially 1. non-local-x is A 2. The let* creates a local environment where local-x is bound to B 3. The question for local-y is which X applies since this is a let* (sequential evaluation of let), local-x applies and Y is set to B 4. (list x y) therefore gives ( B B ) 5. q is therefore set to ( B B ) 1p 1. (lambda (n) (* (+ n 1) 2)) is a lambda expression with one argument (n) 2. The body of the lambda expression is (* (+ n 1) 2)) i.e. the expression returns 2*(n+1) 3. The expression is applied to each element in the list (5 6 7 8) 4. This gives the result (12 14 16 18) which is bound to q DFR/AA/ND 140605 PS tentamen facit Sidan 9 av 15
(defun p (a b c) (list (list 'a a) (list 'b b) (list 'c c) ) ) (defun q (r s) ;line 1 (if (eql 'b (first (first r))) ;line 2 (cons (list 's (list (second (first r)) s)) (rest r)) ;line 3 (cons (first r) (q (rest r) s)) ;line 4 ) ) (setf b (p '(a b) '(c d) '(e f))) (print b) (setf q (q b 'b)) (print q) 1p The rseult is b is and q is ((A (A B)) (B (C D)) (C (E F))) ((A (A B)) (S ((C D) B)) (C (E F))) Förklara stegvis hur proceduren q ovan fungerar med de givna parametrarna. p takes 3 arguments <a> <b> <c> and returns a list ( (A <a>) (B <b>) (C <c>) ) <a> <b> <c> can be of any type - <x> is just a notation to distinguish the formal parameters from their actual values Q is called with 2 actual parameters (i) the list ((A (A B)) (B (C D)) (C (E F))) and (ii) the literal symbol B 1. First call - line 1 checks if the first of the first of parameter 1 is equal to the symbol B i.e. is (first (A (A B)) equal to B answer no 2. First call - line 3 is then executed which is a cons of (A (A B)) with q applied to ((B (C D)) (C (E F))) and the symbol B 3. The second call to q is with parameters ((B (C D)) (C (E F))) and the symbol B 4. Second call line 1 checks if the first of the first of parameter 1 is equal to the symbol B i.e. is (first (B (C D)) equal to B answer yes 5. Second call line 2 work from the inside out a. (first r) (B (C D)) b. (second (first r)) (C D) c. (list (second (first r)) s) ((C D) B) d. (list 's (list (second (first r)) s)) (S ((C D) B)) e. (rest r) (C (E F)) f. (cons (list 's (list (second (first r)) s)) (rest r)) ((S ((C D) B)) (C (E F))) 6. The value returned from the second call ((S ((C D) B)) (C (E F))) 7. This is cons:ed with (first r) from the first call (A (A B)) 8. The final answer is thus ((A (A B)) (S ((C D) B)) (C (E F))) 2p DFR/AA/ND 140605 PS tentamen facit Sidan 10 av 15
Totalt 5p 7. Objektorienterat A. Vad betyder det att en klass är abstrakt? 0,5p B. Varför deklarerar man vissa klasser som abstrakta? 1,0p C. Vad är skillnaden mellan metoder och funktioner? 0,5p D. Vad är virtuella metoder? 0,5p E. Givet följande program skrivet i Java. Vad skrivs ut när programmet körs och varför? Utöver att ange rätt utskrift från programmet så skall du även redovisa för de mekanismer som gör att utskriften blir som den blir. 2,5p class A { void print() { System.out.println("A"); class B extends A { void print() { System.out.println("B"); public class Program { static void print(a a) { a.print(); public static void main(string[] args) { A a = new A(); B b = new B(); A ab = new B(); print(a); print(b); print(ab); Totalt 5p DFR/AA/ND 140605 PS tentamen facit Sidan 11 av 15
A. Det går ej att skapa instanser/objekt av klassen. Klassen kan innehålla abstrakta metoder, men inte nödvändigtvis. Abstrakta klasser kan innehålla icke-abstrakta metoder. Abstrakta klasser används inte för att instansiera objekt utan som basklasser för arv. Man kan se en abstrakt klass som en mall från vilken man kan härleda fler utökade klasser via arv. B. Flera anledningar: 1. Man vill inte att klassen skall instansieras av någon anledning. Kan vara tex ett mattebibliotek med statiska/klass-metoder. Genom att göra klassen abstrakt så förhindrar man att onödiga objekt instansieras från klassen. 2. Den mer vanliga anledningen är att klassen innehåller minst en abstrakt metod (dvs en metod utan implementering/kropp) och då är klassen per automatik abstrakt. C. Metoder eller medlemsfunktioner är subrutiner associerade med ett objekt. Metoder har tillgång till objektets medlemsvariabler. Funktioner är subrutiner som inte är associerade med ett objekt. D. En virtuell metod är en (icke-abstrakt*) metod vars implementation/kropp/beteende kan bli överskriven/omdefinierad av en ärvande klass. Metoder som inte är virtuella kan inte omdefinieras via arv. * Abstrakta metoder är virtuella iom att de måste implementeras via arv, men när man pratar om virtuella metoder så är det som regel icke-abstrakta man syftar till. Att alla abstrakta metoder är virtuella vet man implicit. DFR/AA/ND 140605 PS tentamen facit Sidan 12 av 15
E. Följande kommer skrivas ut: ABB A är en basklass med en printmetod. B är en härledd klass från A som har en egen printmetod och därför skriver över/omdefinierar printmetoden. Klassen Program har också sin egen printmetod, men klassen program är inte inblandad i något arv. Program skapar tre stycken objekt. 1styck instans av klassen A och två stycken instanser av klassen B. Den andra instansen av klassen B lagras i ett dataobjekt av typen A. Detta är fungerar tack vara subtyp-polymorphism som säger att dataobjekt av typen A kan lagra instanser av klassen A och alla subtyper(härledda klasser) av klassen A vilket klassen B är. När anropet till metoden print från metoden main sker så är det metoden print i samma klass som main(dvs Program) som anropas. Denna metod förväntar sig ett objekt av typen A, men tack vara subtyp-polymorphism så accepterar den även subtyper av A. Metoden Program.print anropar i sin tur objektets egna printmetod. När ett objekt av klassen A skickas till metoden Program.print så kommer metoden A.print att anropas och "A" skrivs ut. När ett objekt av klassen B skickas till metoden Program.print så kommer metoden B.print att anropas och "B" skrivs ut. Detta gäller för bägge instanserna av klassen B. Oavsett vad vi angett för datatyp när vi lagrade objektet så är fortfarande objektet en instans av klassen B och kommer "agera" därefter. DFR/AA/ND 140605 PS tentamen facit Sidan 13 av 15
8. Prolog 1. Skriv ett predikat, vand(+inlista, -Utlista), som tar en lista, Inlista, som parameter och returnerar en lista, Utlista, med elementen i omvänd ordning. Exempel på körning:?- vand([1, 2, 3], X). X = [3, 2, 1] Alla predikat som används måste definieras. 3p 2. Beskriv utförligt med egna ord och med kodexempel hur lexerdelen i laborationen omvandlar listan av lexem till en lista av tokens. 2p Totalt 5p (1) vand([], []). /* Basfall 0,5 p */ vand([f R], L1) :- vand(r, L2), append(l2, [F], L1). /* Rekursivt fall 1 p */ append([], L, L). /* Basfall 0,5 p */ append([f T1], L, [F T2]) :- append(t1, L, T2). /* Rekursivt fall 1 p */ Ganska många hade en variant som såg ut så här: vand([], []). vand([h T], [F H]) :- vand(t, F). Det ger som resultat en omvänd ordningsföljd men med de olika elementen i var sin underlista. Jag var snäll och gav 1 p. /* Totalt 3 p */ (2) Den kod jag vill ha med är ungefär följande lexer([], []). lexer([h T], [F S]) :- match(h, F), lexer(t, S). Ett par exempel på matchpredikat för olika typer t ex för ett nyckelord och id eller number och tillhörande förklarande text bör finnas med och så skall man skriva en läsbar kommenterande text också. /* Totalt 2 p */ DFR/AA/ND 140605 PS tentamen facit Sidan 14 av 15
Bilaga A - Grammatik: Pascallik språk 1. [prog] ::= [prog header] [var part] [stat part] 2. [prog header] ::= program id ( input, output ) ; 3. [var part] ::= var [var dec list] 4. [stat part] ::= begin [stat list] end. 5. [var dec list] ::= [var dec] [var dec list] [var dec] 6. [var dec] ::= [id list] : [type] ; 7. [stat list] ::= [stat] [stat list] ; [stat] 8. [stat] ::= [assign stat] 9. [assign stat] ::= id := [expr] 10. [expr] ::= [term] [R1] 11. [R1] ::= e + [term] [R1] 12. [term] ::= [factor] [R2] 13. [R2] ::= e * [factor] [R2] 14. [factor] ::= ( [expr] ) [operand] 15. [type] ::= integer 16. [id list] ::= id [id list], id 17. [operand] ::= id number DFR/AA/ND 140605 PS tentamen facit Sidan 15 av 15