File: README.polymorphic-technical

package info (click to toggle)
bisonc%2B%2B 6.09.02-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,984 kB
  • sloc: cpp: 9,375; ansic: 1,505; fortran: 1,134; makefile: 1,062; sh: 526; yacc: 84; lex: 60
file content (127 lines) | stat: -rw-r--r-- 4,963 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
Polymorphic semantic values are used when the %polymorphic directive is
used. 

E.g., in the specification '%polymorphic TEXT: std::string;'
    'TEXT' is the semantic value tag name used in the grammar specification,
and 
    'std::string' is the C++ type that's used when referring to TEXT. 

The (polymorphic) semantic value type used by the grammar is
'Parser::STYPE_'. By associating non-terminals with a polymorphic semantic
value type (using %type specifications, like '%type <TEXT> identifier') $$
values used by the specified non-terminal automatically use the indicated
semantic value tag name. E.g.,
    identifier:
        IDENTIFIER
        {
            $$ = d_matched;
        }
    ;
When using %type specifications a C++ type can directly be assigned to $$,
and the intended semantic value tag does not have to be specified.

Parser::STYPE_ is available in Parser, but it's defined in parserbase.h. Thus
the type is 'owned' by bisonc++, and cannot be modified in the Parser class.

In addition to the polymorphic tag types defined in the grammar file, a final
%polymorphic specification is added to the generated grammar:
        %polymorphic END_TAG_: EndPolyType_
where both END_TAG_ and EndPolyType_ are (because of the trailing underscores)
names that cannot be used otherwise. A default constructed STYPE_ object
refers to END_TAG_ and contains an End_PolyType value: it is merely used to
ensure that an STYPE_ value is always defined. E.g., it is used in
Parser::setPrecedence.

The parserbase.h file is generated by members of the class Generator, starting
with the skeletons/bisonc++base.h file (in this README file the names used by
default are used). 

When generating files the skeletons use $insert specifications which are
recognized by Generator::filter, calling the corresponding functions specified
in Generator::s_insert (generator/data.cc). The names of those functions are
identical to the names used at the $insert specifications (e.g. '$insert
polymorphic' Generator::polymorphic is called to generate that part of the
generated file). It starts by defining the enum class Tag_ followed by the
definiton of the (empty) class EndPolyType_. E.g., for bisonc++ itself it is:

    // $insert polymorphic
    enum class Tag_
    {
        SYMBOL,
        TERMINAL,
        BLOCK,
        TEXT,
        SIZE_T,
        BOOL,
        END_TAG_
    };
    
    class EndPolyType_
    {};

Semantic value handling is defined in the namespace Meta_ (covered
below). Once the Meta_ namespace has been defined the class ParserBase is
defined ($insert parserbase). Here, STYPE_ is defined by

        using STYPE_ = Meta_::SType;

For each polymorphic tag / C++ type combination the Meta_ namespace defines

    template <typename Tp_>
    struct TagOf;
and    
    template <Tag_ tag>
    struct TypeOf;

and also specializations for the semantic value tags / C++ types, defining,
respectively the associated C++ types and semantic value tags. E.g.,

    template <>
    struct TagOf<std::string>
    {
        static Tag_ const tag = Tag_::TEXT;
    };
and
    template <>
    struct TypeOf<Tag_::TEXT>
    {
        using type = std::string;
    };


Meta_::SType is a wrapper class, derived from std::unique_ptr<Meta_::Base>
It contains the common constructors (default, copy, move), operator= members
for all polymorphic C++ types, an explicit assign member template 
handling the assignments in the operator= members, as in:

    inline SType &SType::operator=(std::string const &value)
    {
        assign< Tag_::TEXT >(value);
        return *this;
    }

and get() members returning the C++ data values of the polymorphic semantic
types (called, assuming STYPE_ value is available) as
value.get<Tag_::TEXT>(). If 'value' does holds a different polymorphic
semantic value then a fatal error results. Finally, it has a member 'tag()'
returning the STYPE_'s Tag_ value.

Next, the Meta_ namespace defines the polymorphic base class Base. Each STYPE_
object contains a pointer to a Base object, which in fact points to an
instantiation of the class template Semantic (see below), where each Semantic
object is constructed for a particular Tag_ (like Semantic_<Tag_::TEXT>,
constructed for the %polymorphic TEXT: std::string polymorphic value. As Base
is the polymorphic base class, all characteristics of the various Semantic
types are accessed via Base members:

        Tag_ tag() const;           returns the Semantic value's tag
        Base *clone() const;        returns a pointer to a newly allocated
                                    copy of the current Semantic object
        void *data() const;         returns a pointer to the data of the
                                    Semantic object.


The class template Semantic has standard constructors and a template
constructor member specifying the required argument(s) and Tag_. Other than
that, its vClone and vData member implementations are provided in parserbase.h