Universität Paderborn - Home Universität Paderborn
Die Universität der Informationsgesellschaft

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