Previous Up Next

Chapter 9  Popts

Popt are used to describe optional data. The in-memory representation of an option records if the data was available and if so, the value of that data.

9.1  Syntax

p_opt_some ::= Psome identifier => { predicate }
p_opt_none ::= Pnone => { predicate }
opt_predicates ::= p_opt_some ‘∣’ p_opt_none
 p_opt_none ‘∣’ p_opt_some
 p_opt_none
 p_opt_some
opt_ty ::= Popt p_ty identifier [p_formals] [: opt_predicates] ;
 

We explain the meaning of this syntax in the remainder of this chapter. All non-terminals not defined in this grammar fragment were defined previously, as follows. Predicates (predicate) are defined in Section 3.3, Pads types (p_ty) and parameter lists (p_formals) in Section 3.6.

9.1.1  Examples

The following declaration indicates that the type oPuint32 describes an optional Puint32.

Popt Puint32 oPuint32;

Precord Pstruct entry1{
  oPuint32 f;
  
’|’;
  oPuint32 g;
}

The Pstruct entry1 uses the type oPuint32 to describe new-line terminated records with the form:

12|24
|23
|
24|

In this case, the representations of both f and g will indicate that the data matched, storing the values 12 and 24, respectively. For the second line, the representation of f will record no match, while g’s will indicate a match with value 23.

A slightly more complex example of options uses predicates to determine if the option matches the input data:

Popt Puint32 even_t : Psome i => {i % 2 == 0};
Popt Puint32 odd_t  : Psome i => {i % 2 != 0};

Precord Pstruct entry3{
  even_t x1;
  odd_t  x2;
  
’|’;
  even_t y1;
  odd_t  y2;
  
’|’;
};

Here, the type even_t matches only even Puint32s, while odd_t matches only odd Puint32s. The Psome clause binds the identifier i to the in-memory representation of the Puint32 found in the data source (if one is found without error). With i bound, it executes the associated predicate, which ensures that the number is even for even_t and odd for odd_t. The type entry3 uses these types to describe newline-terminated data of the form:

12|14|
13|15|
|13|
13|12|

For the first record, x1 will match 12 and y1 will match 14, while x2 and y2 will be marked as not matching. For the second record, x2 and y2 will match instead, with x1 and y1 being marked as no match, etc.

9.1.2  Constraints

Option constraints can have a Psome clause and/or a Pnone clause. The Psome clause specifies a variable and a predicate to execute if the base type of the option is successfully read. If a legal base element is found, the variable is bound to the in-memory representation of the base element and the associated predicate is executed in that context. If the predicate returns true, the

9.1.3  In-line options

For conciseness, Popts can be declared in-line in Pstruct and Punion declarations (cf. Section 5.1.5 and Section 6.1.7).

9.2  Generated library

Currently, Popts are implemented by translation into Punion declarations with two branches. The first branch corresponds to the case where the value is present in the source. The name of this branch is some_OptTy, where OptTy is the name of the Popt type. The second branch corresponds to the case where the value is not present; its name is none_OptTy. For example, the Pads compiler translates the Popt declaration

Popt Ty OptTy;

into

Punion OptTyTrans {
  Ty                some_OptTy;
  
Pcompute Puint32  none_OptTy = 0;
};

and then generates the appropriate code for this declaration.

9.2.1  Tags

Because the compilation of Popts is based on that of Punions, the Pads compiler generates a tag type to describe whether the option was present.

typedef enum OptTy_tag_e OptTy_tag;

enum OptTy_tag_e {
  OptTy_err=
0,
  some_OptTy=
1,
  none_OptTy=
2
  };

Details about the form of this declaration may be found in Section 6.2.1.

9.2.2  In-memory representation

The in-memory representation of an option is a C struct containing a tag field and a val field. The tag indicates whether the option was present. If the tag indicates it was, the value field stores the corresponding value.

typedef union OptTy_u_u OptTy_u;
union OptTy_u_u {
  Ty some_OptTy;                
/* value is present */
};

typedef struct OptTy_s OptTy;
struct OptTy_s {
  OptTy_tag tag;
  OptTy_u val;
};

9.2.3  Mask

The mask of a Popt is a C struct with two fields. The first field, called unionLevel, allows the programmer to toggle behavior at the level of the option as a whole. The second field controls the behavior of various-library functions on the “some” branch of the option, i.e., the branch that corresponds to the value being present in the source.

typedef struct OptTy_m_s OptTy_m;

struct OptTy_m_s {
  Pbase_m unionLevel;
  Ty_m some_OptTy;              
/* nested constraints */
};

9.2.4  Parse descriptor

The parse descriptor of a Popt is a C struct, with all the fields described in Section 3.13. In addition, there is a tag field indicating whether the option appeared in the source and a val field which stores the parse descriptor of the populated branch, represented as a C union.

typedef union OptTy_pd_u_u OptTy_pd_u;
union OptTy_pd_u_u {
  Ty_pd some_OptTy;
  Pbase_pd none_OptTy;          
/* value was not present. none_OptTy = 0 */
};

typedef struct OptTy_pd_s OptTy_pd;
struct OptTy_pd_s {
  Pflags_t pstate;
  Puint32 nerr;
  PerrCode_t errCode;
  Ploc_t loc;
  OptTy_tag tag;
  OptTy_pd_u val;
};

9.2.5  Operations

The operations generated by the Pads compiler for a Popt are those described in Chapter 3. In addition, there is an extra function that converts a value of the tagtype for the option to a string. For a Popt named OptTy, this function has the name OptTy_tag2str. For the Punion OptTy, the prototypes for all the generated functions appear in Figure 9.2.5.


char const *OptTy_tag2str (OptTy_tag which);

Perror_t OptTy_init (P_t *pads,OptTy *rep);

Perror_t OptTy_pd_init (P_t *pads,OptTy_pd *pd);

Perror_t OptTy_cleanup (P_t *pads,OptTy *rep);

Perror_t OptTy_pd_cleanup (P_t *pads,OptTy_pd *pd);

Perror_t OptTy_copy (P_t *pads,OptTy *rep_dst,OptTy *rep_src);

Perror_t OptTy_pd_copy (P_t *pads,OptTy_pd *pd_dst,OptTy_pd *pd_src);

void OptTy_m_init (P_t *pads,OptTy_m *mask,Pbase_m baseMask);

Perror_t OptTy_read (P_t *pads,OptTy_m *m,OptTy_pd *pd,OptTy *rep);

ssize_t OptTy_write2buf (P_t *pads,Pbyte *buf,size_t buf_len,
                         
int *buf_full,OptTy_pd *pd,OptTy *rep);

ssize_t OptTy_write2io (P_t *pads,Sfio_t *io,OptTy_pd *pd,OptTy *rep);

int OptTy_verify (OptTy *rep);

int OptTy_genPD (P_t *pads, OptTy *rep, OptTy_pd *pd);
Figure 9.1: Prototypes of operations generated for the Popt TyOpt.

Read function

The error codes for Popts are:

CodeMeaning
P_NO_ERRIndicates no error occurred
P_OPTION_MATCH_ERRIndicates that no branch of the option parsed without error.

For a option parsing function to return the P_OPTION_MATCH_ERR, the Popt declaration must include a Pnone clause that returns false.

Accumulator functions

Accumulator functions for Popts are described in Chapter 16.

Histogram functions

Histogram functions for Popts are described in Chapter 17.

Clustering functions

Clustering functions for Popts are described in Chapter 18.


Previous Up Next