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


