Generating Software from Specifications WS 2013/14 - File Calendar4Sol.fw
@=~ ~p maximum_input_line_length = infinity This file contains the specification of a calendar processor. It reads a sequence of appointments, represents them by a tree structure. This file contains solutions of Assignment 4, Exercise 11. Explanations of these solutions are marked by ASSIGN 4/11. The following file contains some input for the processor ~O~<cal.ok~>~{~- 1.11. 20:00 "Theater" Thu 14:15 "GSS lecture" Weekday 12:05 "Dinner in Palmengarten" Mon, Thu "Dean's office" 31.12. 23:59 "Jahresende" 12/31 23:59 "End of year" May 1 "Labour Day" Weekday+Sat "Work" Tue - Fri "Use the car" 23.4. - 5.5. "Travel" -- end of file ~} ~O~<cal1.ok~>~{~- Thu 10:00 - 10:15 "Have a break" ~} ASSIGN 3/8 TASK 1: Generate the processor and test it systematically. Make sure that you test for every construct of the language at least one correct and one erroneous example. Use several input files for the erroneous examples to avoid cluttered output. ~O~<cal1.err~>~{~- 1.11 20:00 "A" 1.11. 24:01 "B" 1.11. 20:00 "aa thu 20:00 "A" 33.12. 20:00 "A" ~} ASSIGN 4/11: Erroneous days, months, and day spans: ~O~<cal2.err~>~{~- 12.13. 20:00 "A" 12/33 20:00 "A" 13/12 20:00 "A" Mai 1 "Labour Day" Tue - 2.5. "Think" - ~} ASSIGN 4/11: Test cases for checks made by computations in trees: ~O~<cal3.err~>~{~- 31.04. 15:00 "departure" Thu-Mon 10:15 - 10:00 "Have a break" 01.05. - 30.04. "never" 31.03. 24:01 "arrival" ~} The following file specifies the concrete syntax: ~O~<Calendar.con~>~{ Calendar: Entry+. Entry: Date When Description. Date: DayNum '.' MonNum '.' / MonNum '/' DayNum / Month DayNum / DayNames / GeneralPattern. Date: DayNum '.' MonNum '.' '-' DayNum '.' MonNum '.' / DayName '-' DayName. DayNum: Integer. MonNum: Integer. DayNames: DayName // ','. DayName: Day. GeneralPattern: SimplePattern Modifier / SimplePattern. SimplePattern: 'Weekday' / 'Weekend'. Modifier: '+' DayNames / '-' DayNames. When: Time / Time '-' Time / . ~} ASSIGN 4/11 (1): Insert the mapping specifications as described in the lecture material: ~O~<CalendarChecks.map~>~{ MAPSYM Pattern ::= GeneralPattern SimplePattern. MAPRULE Date: DayNum '.' MonNum '.' < $1 $2 >. Date: MonNum '/' DayNum < $2 $1 >. ~} ASSIGN 4/11 (1): Insert the abstract rule of the rule mapping: ~O~<MapTarget.lido~>~{ RULE: Date ::= DayNum MonNum END; ~} ASSIGN 4/11: The following macros are prepared to contain computations in tree contexts, which check semantic restrictions of the calendar language: ASSIGN 4/11 (2 - 6): Check time spans The following macro is prepared to contain computations in tree contexts, which check semantic restrictions of the calendar language: In the context of time spans the values of the two terminals can be compared directly. ~O~<CalendarChecks2.lido~>~{ RULE: When ::= Time '-' Time COMPUTE IF (LE (Time[2], Time[1]), message (ERROR, "wrong time span", 0, COORDREF)); END; ~} ASSIGN 4/11 (7): Check day in a month Attributes <code>DayNum.val</code> and <code>MonNum.val</code>have to be introduced to propagate the values of the terminal <code>Integer</code> into a context where they can be compared: ~O~<CalendarChecks7.lido~>~{ ATTR val:int; RULE: DayNum ::= Integer COMPUTE DayNum.val = Integer; END; RULE: MonNum ::= Integer COMPUTE MonNum.val = Integer; END; RULE: Date ::= DayNum MonNum COMPUTE IF (wrongDate (DayNum.val, MonNum.val), message (ERROR, "wrong date", 0, COORDREF)); END; RULE: Date ::= Month DayNum COMPUTE IF (wrongDate (DayNum.val, Month), message (ERROR, "wrong date", 0, COORDREF)); END; ~} ASSIGN 4/11 (8): Check spans of days in a week, and in a year The following checks are solved similar as the previous one: ~O~<CalendarChecks8.lido~>~{ RULE: DayName ::= Day COMPUTE DayName.val = Day; END; RULE: Date ::= DayName '-' DayName COMPUTE IF (LE (DayName[2].val, DayName[1].val), message (ERROR, "wrong span of days in a week", 0, COORDREF)); END; RULE: Date ::= DayNum '.' MonNum '.' '-' DayNum '.' MonNum '.' COMPUTE IF (LE (dayInYear (DayNum[2].val, MonNum[2].val), dayInYear (DayNum[1].val, MonNum[1].val)), message (ERROR, "wrong span of days in a year", 0, COORDREF)); END; ~} ASSIGN 3/8 TASK 2: Check the meaning of the following token specifications. Extend the input language by comments. What kind of comments do you think fits best to the style of this language? Specify it and test the processor. The appointments of this language will usually be written one per line. So, line comments would fit best to the language. I specified Ada comments. ~O~<Calendar.gla~>~{ Description: C_STRING_LIT Integer: PASCAL_INTEGER Day: $Mon|Tue|Wed|Thu|Fri|Sat|Sun [mkDay] Time: $(([0-9]|1[0-9]|2[0-3]):[0-5][0-9]) [mkTime] ADA_COMMENT Month: $Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec [mkMonth] ~} ASSIGN 3/8 TASK 3: The C module below implements the two token coding functions mkDay and mkTime. Understand what they compute. Then extend your language by a facility to write abbreviated names of months, too, e.g. May 1 "Labour Day" Which specification types do you need to change? A new alternative for Date is inserted in the concrete syntax (.con). The token specification for Month is added (.gla). The coding function is implemented in the C module (.h, .c) Correct and erroneous test cases are added. You can make the extensions according to the way the names of Days are specified. ASSIGN 3/8 TASK 4: Change the specification of the token Time. (Keep the current specification, in order to undo this change after this experiment.) Make time to be a nonterminal which derives the hours and minutes separated by a colon. Any checks, whether the time is correct may be deferred to the semantic analysis phase. Check carefully how the notation of Time now differs from the previous version. Which one do you prefer? I inserted the productions Time: Hour ':' Minute. Hour: Integer. Minute: Integer. into the concrete syntax and deleted the token specification for Time. The check for correct time notations is then deferred to semantic analysis. Now it is possible to insert white space into time notations e.g. 10 : 25. I prefer the original notation. ~O~<Calendar.head~>==~{ #include "csm.h" #include "Calendar.h" ~} ~O~<Calendar.h~>==~{ extern void mkDay (char *, int, int *, int*); extern void mkTime (char *, int, int *, int*); extern void mkMonth (char *, int, int *, int*); extern int dayInYear (int day, int mon); extern int wrongDate (int day, int mon); ~} ~O~<Calendar.c~>==~{ #include <string.h> #include "Calendar.h" void mkDay (char *d, int l, int *c, int *i) { switch (d[0]) { case 'F': *i = 5; break; case 'M': *i = 1; break; case 'W': *i = 3; break; case 'S': *i = (d[1] == 'a'? 6 : 7); break; case 'T': *i = (d[1] == 'u' ? 2 : 4); break; } } void mkTime (char *t, int l, int *c, int *i) { char *colon = strchr (t, ':'); int hours, mins; *colon = '\0'; hours = atoi (t); mins = atoi (colon + 1); *colon = ':'; *i = hours*60 + mins; } void mkMonth (char *m, int l, int *c, int *i) { switch (m[0]) { case 'A': *i = (m[1] == 'p' ? 4 : 8); break; case 'D': *i = 12; break; case 'F': *i = 2; break; case 'J': *i = (m[1] == 'a' ? 1 : (m[2] == 'n' ? 6 : 7)); break; case 'M': *i = (m[2] == 'r' ? 3 : 5); break; case 'N': *i = 11; break; case 'O': *i = 10; break; case 'S': *i = 9; break; } } /* day in year = day + (month-1)*28 + delta[month-1] For a leap year all but the first of the delta values have to be incremented by 1 */ int delta[] = {0,3,3,6,8,11,13,16,19,21,24,26,29}; int dayInYear (int day, int month) { if (day <= 0 || day > 31 || month <= 0 || month > 12) return 1; return day + (month-1)*28 + delta[month-1]; } int wrongDate (int day, int month) { if (day <= 0 || day > 31 || month <= 0 || month > 12) return 1; if (dayInYear (day, month) > month*28 + delta[month]) return 1; return 0; } ~}
Generiert mit Camelot | Probleme mit Camelot? | Geändert am: 13.11.2013