Generating Software from Specifications WS 2013/14 - File CalendarCheck.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, and performs some checks and computations as required in Assignment 4, Exercise 11. The following files contain correct input for the processor ~O~<cal.ok~>~{~- 1.11. 20:00 "Theater" Thu 14:15 "GSS lecture" 1.5. 9:15 "Meeting" 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" -- end of file ~} ~O~<cal1.ok~>~{~- Thu 10:00 - 10:15 "Have a break" ~} The following files contain erroneous input for the processor ~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" ~} ~O~<cal2.err~>~{~- 12.13. 20:00 "A" 12/33 20:00 "A" 13/12 20:00 "A" Mai 1 "Labour Day" - ~} ~O~<cal3.err~>~{~- 31.4. 9:00 "not in April" 1.13. 9:00 "not in any year" ~} The following file specifies the concrete syntax: ~O~<Calendar.con~>~{ Calendar: Entries. Entries: Entries Entry / Entry. Entry: DateDescr When Description. DateDescr: Date / DayNames / GeneralPattern. Date: DayNum '.' MonNum '.' / MonNum '/' DayNum / Month DayNum. DayNum: Integer. MonNum: Integer. DayNames: DayNames ',' DayName / DayName. DayName: Day. GeneralPattern: SimplePattern Modifier / SimplePattern. SimplePattern: 'Weekday' / 'Weekend'. Modifier: '+' DayNames / '-' DayNames. When: Time / Time '-' Time / . ~} The non-literal tokens are specified as follows: ~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] ~} A 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 >. ~} The target rule of the rule mapping: ~O~<MapTarget.lido~>~{ RULE: Date ::= DayNum MonNum END; ~} The correctness of time spans is checked. ~O~<CalendarChecks1.lido~>~{ RULE: When ::= Time '-' Time COMPUTE IF (LE (Time[2], Time[1]), message (ERROR, "wrong time span", 0, COORDREF)); END; ~} Attributes <code>DayNum.val</code> and <code>MonNum.val</code> are introduced to propagate the values of the terminal <code>Integer</code> into a context where they can be compared: ~O~<CalendarChecks2.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; ~} INSERT SOLUTIONS OF ASSIGNMENT 4 HERE: Use a single FunnelWeb macro for each subtask. Subtask 1: Store and print the number of days in the year: ~O~<CalCheck-1.lido~>~{ ~} Subtask 2: Compute the minimal date that occurs in the input, by explicit bottom-up propagation: ~O~<CalCheck-2.lido~>~{ ~} Subtask 3: Deactivate the solution of subtask 2. Use a CONSTITUENTS-WITH construct to compute the earliest date ~O~<CalCheck-3.lido~>~{~- ~} Subtask 4: Propagate the minimal date down to each Date and output it there: ~O~<CalCheck-4.lido~>~{ ~} Subtask 5: Deactivate the solution of subtask 4. Propagate the minimal date down to every Date using an INCLUDING construct, and output it there: ~O~<CalCheck-5.lido~>~{ ~} Subtask 6: Deactivate the solutions of subtasks 1 to 5. Use Symbol computations wherever possible. ~O~<CalCheck-6.lido~>~{ ~} ~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] Delta values for a non-leap year: int delta[] = {0,3,3,6,8,11,13,16,19,21,24,26,29}; leap year: int delta[] = {0,3,4,7,9,12,14,17,20,22,25,27,30}; */ int delta[] = {0,3,4,7,9,12,14,17,20,22,25,27,30}; 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