Generating Software from Specifications WS 2013/14 - File StreamsSol.fw
@=~ ~p maximum_input_line_length = infinity This file specifies a little domain-specific language, which allows to compose streams from declared components. A Streams program consists of a sequence of definitions followed by a sequence of streams. Each definition introduces entities of one of three kinds: sources, sinks, and connectors. Each entity is bound to a name, and is defined to have a certain capacity given by a non-negative number. The name of the entities have to be pairwise different. A stream in the second part of the program consists of a source and a sink, connected by a sequence of connectors. The source shall run on its full capacity. Hence, the capacity of the sink and of any connector in that stream must be at least as great as the capacity of the source of that stream. Here is an example for a correct Streams program: ~O~<Streams.ok~>~{~- source: a 10, b 5; sink: x 20, y 5; connector: k 7, h 9, f 15, g 3; a -> f -> x; b -> h -> h -> k -> y; b -> x; ~} Here is an example for an erroneous Streams program: ~O~<Streams.err~>~{~- source: a 10, b 5; sink: x 20, y 5, z 1; /* z is multiply defined */ connector: k 7, h 9, f 15, g 3; connector: z 5; /* z is multiply defined */ a -> q -> x; /* q is undefined */ d -> h -> x; /* d is undefined */ a -> k -> x; /* k has too little capacity */ a -> y; /* y has too little capacity */ y -> x; /* y must be a source */ b -> h -> a; /* a must be a sink */ b -> a -> x; /* a must be a connector */ ~} The concrete syntax is specified as follows: ~O~<Streams.con~>~{ Program: Definitions Streams. Definitions: Definition*. Streams: Stream*. Definition: Kind ':' Items ';'. Kind: 'source' / 'sink' / 'connector'. Items: Items ',' Item / Item. Item: Name Number. Name: Ident. Stream: Source Tail. Tail: Connector Tail / '->' Sink ';'. Connector: '->' Ident. Source: Ident. Sink: Ident. ~} The productions for Stream are chosen this way to avoid LALR(1) conflicts. Ident being reduced to three different nonterminals is crucial for that situation. he non-literal token specifications: ~O~<Streams.gla~>~{ Ident: PASCAL_IDENTIFIER Number: PASCAL_INTEGER C_COMMENT ~} Algol-like scope rules are specified for this language: ~O~<NameAnalysis.specs~>~{ $/Name/AlgScope.gnrc:inst ~} The module roles for defining and applied identifiers are used in the standard way. ~O~<StreamsName.lido~>~{ SYMBOL Program INHERITS RootScope END; CLASS SYMBOL IdentOcc: Sym: int; CLASS SYMBOL IdentOcc COMPUTE SYNT.Sym = TERM; END; SYMBOL Name INHERITS IdentOcc, IdDefScope END; SYMBOL Source INHERITS IdentOcc, IdUseEnv, ChkIdUse END; SYMBOL Sink INHERITS IdentOcc, IdUseEnv, ChkIdUse END; SYMBOL Connector INHERITS IdentOcc, IdUseEnv, ChkIdUse END; ~} The following property is used to detect multiple definitions: ~O~<StreamsMult.pdl~>~{~- Defs: int; ~} The property Defs is used to detect and report multiple definitions: ~O~<StreamsMult.lido~>~{ SYMBOL Program COMPUTE SYNT.GotDefs = CONSTITUENTS Name.GotDefs; END; SYMBOL Name COMPUTE SYNT.GotDefs = SetDefs (THIS.Key, 1, 2); IF (GT (GetDefs (THIS.Key, 0), 1), message (ERROR, CatStrStr ("multiply defined: ", StringTable (THIS.Sym)), 0, COORDREF)) <- INCLUDING Program.GotDefs; END; ~} The property Kind distinguishes the three kinds of entities (source, sink, connector) by integral codes, which are defined by cpp macros at the end of the specification file. ~O~<StreamsKind.pdl~>~{~- Kind: int; ~} The Kind property is stored in each declaration context. The its value is taken from the INCLUDING definition. In the contexts of the symbols Source, Sink, Connector the required kind is checked: ~O~<StreamsKind.lido~>~{~- SYMBOL Program COMPUTE SYNT.GotKind = CONSTITUENTS Item.GotKind; END; SYMBOL Kind, Definition: Kind: int; RULE: Definition ::= Kind ':' Items ';' COMPUTE Definition.Kind = Kind.Kind; END; RULE: Kind ::= 'source' COMPUTE Kind.Kind = isSource; END; RULE: Kind ::= 'sink' COMPUTE Kind.Kind = isSink; END; RULE: Kind ::= 'connector' COMPUTE Kind.Kind = isConnector; END; RULE: Item ::= Name Number COMPUTE Item.GotKind = ResetKind (Name.Key, INCLUDING Definition.Kind); END; SYMBOL Source COMPUTE IF (NE (GetKind (THIS.Key, isSource), isSource), message (ERROR, CatStrStr ("must be a source: ", StringTable (THIS.Sym)), 0, COORDREF)) <- INCLUDING Program.GotKind; END; SYMBOL Sink COMPUTE IF (NE (GetKind (THIS.Key, isSink), isSink), message (ERROR, CatStrStr ("must be a sink: ", StringTable (THIS.Sym)), 0, COORDREF)) <- INCLUDING Program.GotKind; END; SYMBOL Connector COMPUTE IF (NE (GetKind (THIS.Key, isConnector), isConnector), message (ERROR, CatStrStr ("must be a connector: ", StringTable (THIS.Sym)), 0, COORDREF)) <- INCLUDING Program.GotKind; END; ~} The property Capacity stores the declared capacity of each entity. ~O~<StreamsCapacity.pdl~>~{~- Capacity: int; ~} The property Capacity is set for each Item. The flow of a stream is determined by its source. For its connectors and its sink it is checked that they have at least that capacity. ~O~<StreamsCapacity.lido~>~{~- SYMBOL Program COMPUTE SYNT.GotCapacity = CONSTITUENTS Item.GotCapacity; END; RULE: Item ::= Name Number COMPUTE Item.GotCapacity = ResetCapacity (Name.Key, Number); END; SYMBOL Stream: Flow: int; RULE: Stream ::= Source Tail COMPUTE Stream.Flow = GetCapacity (Source.Key, 0) <- INCLUDING Program.GotCapacity; END; SYMBOL Connector COMPUTE IF (GT (INCLUDING Stream.Flow, GetCapacity (THIS.Key, infinite)), message (ERROR, CatStrStr ("too little capacity: ", StringTable (THIS.Sym)), 0, COORDREF)) <- INCLUDING Program.GotCapacity; END; SYMBOL Sink COMPUTE IF (GT (INCLUDING Stream.Flow, GetCapacity (THIS.Key, infinite)), message (ERROR, CatStrStr ("too little capacity: ", StringTable (THIS.Sym)), 0, COORDREF)) <- INCLUDING Program.GotCapacity; END; ~} ~O~<Streams.HEAD.phi~>~{ #include "Streams.h" ~} ~O~<Streams.h~>~{ #ifndef isSource #define isSource 1 #define isSink 2 #define isConnector 3 #define infinite 99999 #endif ~} ~O~<Streams.c~>~{ ~}
Generiert mit Camelot | Probleme mit Camelot? | Geändert am: 11.12.2013