diff --git a/yo/advancedtemplates/aliases.yo b/yo/advancedtemplates/aliases.yo new file mode 100644 index 00000000..adf16bd6 --- /dev/null +++ b/yo/advancedtemplates/aliases.yo @@ -0,0 +1,99 @@ +Typedefs are commonly defined using the tt(typedef) keyword. In addition, +C++11 allows the ti(using) keyword to associate a type and and identifier, but +different from ti(typedef) it does em(not) define a type. In practice +tt(typedef) and tt(using) can be used interchangeably. + +In addition to function and class templates, C++11 also uses templates to +define an alias for a set of types. This is called a emi(template +alias). Template aliases can be specialized. The name of a template alias +spacialization is a type name. + +The name of a template alias is a template name. + +A template argument for a template template parameter is either a class +template or it is a template alias (expressed as 'id expression' + +Alias declarations cannot be (partially, explicitly) specialized. Template +aliases can be specialized. + +Examples: + verb( +template struct X {...}; + +template + using VecT = vector>; + +Vec vi; // same as vector> vi; + + +-------------------- +template alias (formerly known as "template typedef") +How can we make a template that's "just like another template" but possibly with a couple of template arguments specified (bound)? Consider: + + + template + using Vec = std::vector>; // standard vector using my allocator + + Vec fib = { 1, 2, 3, 5, 8, 13 }; // allocates elements using My_alloc + + vector> verbose = fib; // verbose and fib are of the same type + +The keyword using is used to get a linear notation "name followed by what it refers to." We tried with the conventional and convoluted typedef solution, but never managed to get a complete and coherent solution until we settled on a less obscure syntax. + +Specialization works (you can alias a set of specializations but you cannot specialize an alias) For example: + + template + struct int_exact_traits { // idea: int_exact_trait::type is a type with exactly N bits + typedef int type; + }; + + template<> + struct int_exact_traits<8> { + typedef char type; + }; + + template<> + struct int_exact_traits<16> { + typedef char[2] type; + }; + + // ... + + template + using int_exact = typename int_exact_traits::type; // define alias for convenient notation + + int_exact<8> a = 7; // int_exact<8> is an int with 8 bits + +In addition to being important in connection with templates, type aliases can also be used as a different (and IMO better) syntax for ordinary type aliases: + + +typedef void (*PFD)(double); // C style +using PF = void (*)(double); // using plus C-style type +using P = [](double)->void; // using plus suffix return type + +------------------------------------------------- +template +using Dictionary = std::map< std::string, T >; + +Dictionary ints; +ints[ "one" ] = 1; +ints[ "two" ] = 2; + +---------------------- the really useful case: + +#include + +template class Container> +struct Wrapper: public Container +{}; + +template +using VT = std::vector; + +int main() +{ + Wrapper wi; + // Wrapper wi2; ERR! +} + + diff --git a/yo/concrete.yo b/yo/concrete.yo index 36cae818..d2e57559 100644 --- a/yo/concrete.yo +++ b/yo/concrete.yo @@ -145,8 +145,8 @@ includefile(concrete/bisonflex) subsubsect(The scanner using a polymorphic semantic value type) includefile(concrete/semscanner.yo) - lsubsect(BISONSEM)(Using unrestricted unions semantic values with Bisonc++) - includefile(concrete/unrestricted) // TODO + subsect(Using unrestricted unions as semantic values (C++11)) + includefile(concrete/unrestricted) diff --git a/yo/concrete/polymorphic.yo b/yo/concrete/polymorphic.yo index 71f62c37..f4003d7c 100644 --- a/yo/concrete/polymorphic.yo +++ b/yo/concrete/polymorphic.yo @@ -2,17 +2,15 @@ Bisonc++ may use polymorphic semantic values. How this is realized is covered in this section. The described method is a direct result of a suggestion initially brought forward by Dallas A. Clement in September 2007. -One may wonder why a tt(union) is still used by Bisonc++ as bf(C++) offers +One may wonder why tt(union)s are still used by Bisonc++, as bf(C++) offers inherently superior constructs to combine multiple types into one type. The -bf(C++) way to combine types into one type is by defining a polymorphic base -class and a series of derived classes implementing the alternative data -types. Bisonc++ supports the tt(union) approach (and the unrestricted unions -with C++11) for various (e.g., backward compatibility) -reasons. bi(Bison) and bi(bison++) both support the tt(%union) directive. +support by C++11 for unrestricted unions may result in tt(union)s being +re-evaluated, but bf(C++) traditionally offers a good alternative for the use +of tt(union)s: a polymorphic base class and a series of derived classes +implementing the alternative data types. -An alternative to using a tt(union) is using a polymorphic base class. Such a -class is developed below (the class tt(Base)). As it is a polymorphic -base class it has the following characteristics: +Below, a polymorphic base class (the class tt(Base)) is developed. As it is a +polymorphic base class it has the following characteristics: itemization( it() Its destructor is virtual (and has a default implementation); it() Objects of the derived classes may be obtained from a diff --git a/yo/concrete/unrestricted.yo b/yo/concrete/unrestricted.yo new file mode 100644 index 00000000..50fa49c7 --- /dev/null +++ b/yo/concrete/unrestricted.yo @@ -0,0 +1,15 @@ +Unions revived at the introduction of C++11's unrestricted unions. +In this section we'll have a look at how to used them as +semantic values in a Bisonc++ generated parser. + + + Bisonc++'s semantic value must support + itemization( + itt(int) values; + itt(textual) values of type tt(string); + ) + + + +Here is tt(Semantic)'s interface: + verbinclude(poly/semantic/semantic.h) diff --git a/yo/concrete/unrestricted/CLASSES b/yo/concrete/unrestricted/CLASSES new file mode 100644 index 00000000..ca846c56 --- /dev/null +++ b/yo/concrete/unrestricted/CLASSES @@ -0,0 +1 @@ +semantic diff --git a/yo/concrete/unrestricted/icmconf b/yo/concrete/unrestricted/icmconf new file mode 100644 index 00000000..eeb9d173 --- /dev/null +++ b/yo/concrete/unrestricted/icmconf @@ -0,0 +1,112 @@ + // Inspect the following #defines. Change them to taste. If you don't + // need a particular option, change its value into an empty string + + // should commands be echoed (ON) or not (OFF) ? +#define USE_ECHO ON + + + // The final program and source containing main(): + // =============================================== + + // define the name of the program to create: +#define BINARY "../../poly" + + // define the name of the source containing main(): +#define MAIN "main.cc" + + // #defines used for compilation and linking: + // ========================================== + + // define the compiler to use: +#define COMPILER "g++" + + // define the compiler options to use: +#define COMPILER_OPTIONS "-g --std=c++0x -Wall -O2" + + // define the pattern to locate sources in a directory: +#define SOURCES "*.cc" + + // define the options used for linking: +#define LINKER_OPTIONS "-s" + + // define any additional libraries BINARY may need: +#define ADD_LIBRARIES "bobcat" + + // define any additional paths (other than the standard paths) the + // additional libraries are located in: +#define ADD_LIBRARY_PATHS "" + + // #defines used for the final product: + // ==================================== + +#define BIN_INSTALL "/usr/local/bin" + + + + // Some advanced #defines, used to create parsers and lexical scanners + // =================================================================== + + + // Lexical Scanner section + // ======================= + + // Should a lexical scanner be constructed? If so, define the subdirectory + // containing the scanner's specification file. +#define SCANNER_DIR "scanner" + + // What is the program generating the lexical scanner? +#define SCANGEN "flex" + + // Flags to provide SCANGEN with: +#define SCANFLAGS "-I" + + // Name of the lexical scanner specification file +#define SCANSPEC "lexer" + + // Name of the file generated by the lexical scanner +#define SCANOUT "yylex.cc" + + + // Parser section + // ============== + + // Should a parser be constructed? If so, define the subdirectory + // containing the parser's specification file +#define PARSER_DIR "parser" + + // If a parser must be constructed, should the script (provided in the + // skeleton file parser/gramspec/grambuild) `parser/gramspec/grambuild' + // **NOT** be called? If it must NOT be called, comment out the following + // #define directive: +// #define GRAMBUILD + + // What it the program generating a parser? +#define PARSGEN "bisonc++" + + // What it the grammar specificication file? +#define PARSSPEC "grammar" + + // Flags to provide PARSGEN with: +#define PARSFLAGS "-V -l" + + // Name of the file generated by the parser generator containing the + // parser function +#define PARSOUT "parse.cc" + + + + // Additional defines, which should normally not be modified + // ========================================================= + + // Directory below this directory to contain temporary results +#define TMP_DIR "tmp" + + // Local program library to use (change to an empty string if you want to + // use the object modules themselves, rather than a library) +#define LIBRARY "modules" + + // The extension of object modules: +#define OBJ_EXT ".o" + + // below #define DEFCOM "program" or "library" may be added by icmstart +#define DEFCOM "program" diff --git a/yo/concrete/unrestricted/input b/yo/concrete/unrestricted/input new file mode 100644 index 00000000..efcda42d --- /dev/null +++ b/yo/concrete/unrestricted/input @@ -0,0 +1,4 @@ +abc(def); +xyz = 5; + + diff --git a/yo/concrete/unrestricted/main.cc b/yo/concrete/unrestricted/main.cc new file mode 100644 index 00000000..45ca5e16 --- /dev/null +++ b/yo/concrete/unrestricted/main.cc @@ -0,0 +1,12 @@ +#include "main.ih" + +int main(int argc, char **argv) +{ + Parser parser; + + parser.setDebug(argc == 1); + + parser.parse(); + + return 0; +} diff --git a/yo/concrete/unrestricted/main.ih b/yo/concrete/unrestricted/main.ih new file mode 100644 index 00000000..06a98526 --- /dev/null +++ b/yo/concrete/unrestricted/main.ih @@ -0,0 +1,6 @@ +#include +#include +#include + +#include "parser/preinclude.h" +#include "parser/parser.h" diff --git a/yo/concrete/unrestricted/parser/grammar b/yo/concrete/unrestricted/parser/grammar new file mode 100644 index 00000000..5a49959b --- /dev/null +++ b/yo/concrete/unrestricted/parser/grammar @@ -0,0 +1,33 @@ +%class-name Parser + +%filenames parser +%parsefun-source parse.cc +%scanner ../scanner/scanner.h +// %debug + +%baseclass-preinclude preinclude.h + +%stype Semantic + +%token INT IDENTIFIER + +%% + +rules: + rules rule +| + rule +; + +rule: + IDENTIFIER '(' IDENTIFIER ')' ';' + { + cout << $1 << " " << $3 << '\n'; + } +| + IDENTIFIER '=' INT ';' + { + cout << $1 << " " << $3 << '\n'; + } +; + diff --git a/yo/concrete/unrestricted/parser/parser.h b/yo/concrete/unrestricted/parser/parser.h new file mode 100644 index 00000000..72beedf4 --- /dev/null +++ b/yo/concrete/unrestricted/parser/parser.h @@ -0,0 +1,53 @@ +#ifndef Parser_h_included +#define Parser_h_included + +// $insert baseclass +#include "parserbase.h" +// $insert scanner.h +#include "../scanner/scanner.h" + + +#undef Parser +class Parser: public ParserBase +{ + // $insert scannerobject + Scanner d_scanner; + + public: + Parser(); + int parse(); + + private: + void error(char const *msg); // called on (syntax) errors + int lex(); // returns the next token from the + // lexical scanner. + void print(); // use, e.g., d_token, d_loc + + // support functions for parse(): + void executeAction(int ruleNr); + void errorRecovery(); + int lookup(bool recovery); + void nextToken(); +}; + +inline void Parser::error(char const *msg) +{ + std::cerr << msg << '\n'; +} + +// $insert lex +inline int Parser::lex() +{ + return d_scanner.yylex(); +} + +inline void Parser::print() // use d_token, d_loc +{} + +inline Parser::Parser() +: + d_scanner(&d_val__) +{} + + +#endif diff --git a/yo/concrete/unrestricted/parser/parser.ih b/yo/concrete/unrestricted/parser/parser.ih new file mode 100644 index 00000000..b140119d --- /dev/null +++ b/yo/concrete/unrestricted/parser/parser.ih @@ -0,0 +1,6 @@ + // Include this file in the sources of the class Parser. + +// $insert class.h +#include "parser.h" + +using namespace std; diff --git a/yo/concrete/unrestricted/parser/preinclude.h b/yo/concrete/unrestricted/parser/preinclude.h new file mode 100644 index 00000000..669dac33 --- /dev/null +++ b/yo/concrete/unrestricted/parser/preinclude.h @@ -0,0 +1,6 @@ +#ifndef INCLUDED_PREINCLUDE_H_ +#define INCLUDED_PREINCLUDE_H_ + +#include "../semantic/semantic.h" + +#endif diff --git a/yo/concrete/unrestricted/scanner/lexer b/yo/concrete/unrestricted/scanner/lexer new file mode 100644 index 00000000..321a3d04 --- /dev/null +++ b/yo/concrete/unrestricted/scanner/lexer @@ -0,0 +1,34 @@ +%{ + #define SKIP_FLEXLEXER_ + #include "scanner.ih" + + #include "../parser/preinclude.h" + #include "../parser/parserbase.h" +%} + +%option yyclass="Scanner" outfile="yylex.cc" +%option c++ 8bit warn noyywrap yylineno +%option debug + +%% + +[ \t]+ // skip white space +\n // same + +[0-9]+ { + *d_semval = Semantic(Semantic::INT, yytext); + return Parser::INT; + } + +[a-zA-Z_][a-zA-Z0-9_]* { + *d_semval = Semantic(Semantic::IDENTIFIER, yytext); + return Parser::IDENTIFIER; + } + +. return yytext[0]; + + +%% + + + diff --git a/yo/concrete/unrestricted/scanner/scanner.h b/yo/concrete/unrestricted/scanner/scanner.h new file mode 100644 index 00000000..76c084b0 --- /dev/null +++ b/yo/concrete/unrestricted/scanner/scanner.h @@ -0,0 +1,25 @@ +#ifndef SCANNER_H_ +#define SCANNER_H_ + +#include "../semantic/semantic.h" + +#if ! defined(SKIP_FLEXLEXER_) && ! defined(SYSINC_FLEXLEXER_H_) +#include +#define SYSINC_FLEXLEXER_H_ +#endif + +class Scanner: public yyFlexLexer +{ + Semantic *d_semval; // received fm the parser + + public: + Scanner(Semantic *semval); + int yylex(); +}; + +inline Scanner::Scanner(Semantic *semval) +: + d_semval(semval) +{} + +#endif diff --git a/yo/concrete/unrestricted/scanner/scanner.ih b/yo/concrete/unrestricted/scanner/scanner.ih new file mode 100644 index 00000000..c0b93be0 --- /dev/null +++ b/yo/concrete/unrestricted/scanner/scanner.ih @@ -0,0 +1,30 @@ +/* + Declare here + what's only used in the Scanner class + and let Scanner's sources include "scanner.ih" +*/ + +#include "scanner.h" + +//#include +// #include +// #include +// #include + +/* + In the current Debian distribution of flex, YY_CURRENT_BUFFER and YY_START + are not available to members of the flex-generated class (See `Values + Available To The User' in the flex info-file). Use the following macros to + make these values available. (Note that the need for these defines may be + superfluous in the near future): +*/ +// uncomment if you want to use YY_CURRENT_BUFFER in the scanner's members: +/* +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +*/ +// uncomment if you want to use YY_START in the scanner's members: +// #define YY_START (((yy_start) - 1) / 2) + +// end of scanner.ih diff --git a/yo/concrete/unrestricted/semantic/destructor.cc b/yo/concrete/unrestricted/semantic/destructor.cc new file mode 100644 index 00000000..48ec2864 --- /dev/null +++ b/yo/concrete/unrestricted/semantic/destructor.cc @@ -0,0 +1,7 @@ +#include "semantic.ih" + +Semantic::~Semantic() +{ + if (d_int.first == IDENTIFIER) + d_str.second.~string(); // destroy the string's memory +} diff --git a/yo/concrete/unrestricted/semantic/frame b/yo/concrete/unrestricted/semantic/frame new file mode 100644 index 00000000..f84bcd92 --- /dev/null +++ b/yo/concrete/unrestricted/semantic/frame @@ -0,0 +1,5 @@ +#include "semantic.ih" + +Semantic:: +{ +} diff --git a/yo/concrete/unrestricted/semantic/operatorassign.cc b/yo/concrete/unrestricted/semantic/operatorassign.cc new file mode 100644 index 00000000..e015530c --- /dev/null +++ b/yo/concrete/unrestricted/semantic/operatorassign.cc @@ -0,0 +1,8 @@ +#include "semantic.ih" + +Semantic &Semantic::operator=(Semantic const &rhs) +{ + Semantic tmp(rhs); + swap(tmp); + return *this; +} diff --git a/yo/concrete/unrestricted/semantic/operatorinsert.cc b/yo/concrete/unrestricted/semantic/operatorinsert.cc new file mode 100644 index 00000000..01572e37 --- /dev/null +++ b/yo/concrete/unrestricted/semantic/operatorinsert.cc @@ -0,0 +1,15 @@ +#include "semantic.ih" + +std::ostream &operator<<(std::ostream &out, Semantic const &obj) +{ + switch (obj.d_int.first) + { + case Semantic::INT: + return out << obj.d_int.second; + + case Semantic::IDENTIFIER: + return out << obj.d_str.second; + } + + return out << "<*UNDEFINED*>"; +} diff --git a/yo/concrete/unrestricted/semantic/semantic.h b/yo/concrete/unrestricted/semantic/semantic.h new file mode 100644 index 00000000..a7b8d870 --- /dev/null +++ b/yo/concrete/unrestricted/semantic/semantic.h @@ -0,0 +1,38 @@ +#ifndef INCLUDED_SEMANTIC_ +#define INCLUDED_SEMANTIC_ + +#include +#include + +union Semantic +{ + friend std::ostream &operator<<(std::ostream &out, Semantic const &obj); + + std::pair d_int; + std::pair d_str; + + public: + enum Type + { + UNDEFINED, + INT, + IDENTIFIER + }; + + Semantic(); + Semantic(Type type, char const *txt); + Semantic(Semantic const &other); // 2 + ~Semantic(); + + Semantic &operator=(Semantic const &rhs); + + void swap(Semantic &other); + +}; + +inline Semantic::Semantic() +: + d_int {UNDEFINED, 0} +{} + +#endif diff --git a/yo/concrete/unrestricted/semantic/semantic.ih b/yo/concrete/unrestricted/semantic/semantic.ih new file mode 100644 index 00000000..8d68dc27 --- /dev/null +++ b/yo/concrete/unrestricted/semantic/semantic.ih @@ -0,0 +1,6 @@ +#include "semantic.h" + +#include +#include + +using namespace std; diff --git a/yo/concrete/unrestricted/semantic/semantic1.cc b/yo/concrete/unrestricted/semantic/semantic1.cc new file mode 100644 index 00000000..ba9e765b --- /dev/null +++ b/yo/concrete/unrestricted/semantic/semantic1.cc @@ -0,0 +1,14 @@ +#include "semantic.ih" + +Semantic::Semantic(Type type, char const *txt) +{ + d_int.first = static_cast(type); + + if (type == IDENTIFIER) + new (&d_str.second) string(txt); + else + { + istringstream in(txt); + in >> d_int.second; + } +} diff --git a/yo/concrete/unrestricted/semantic/semantic2.cc b/yo/concrete/unrestricted/semantic/semantic2.cc new file mode 100644 index 00000000..79494118 --- /dev/null +++ b/yo/concrete/unrestricted/semantic/semantic2.cc @@ -0,0 +1,9 @@ +#include "semantic.ih" + +Semantic::Semantic(Semantic const &other) +: + d_int(other.d_int) // blunt copy of d_int +{ + if (d_int.first == IDENTIFIER) // if a string: copy it + new (&d_str.second) string(other.d_str.second); +} diff --git a/yo/concrete/unrestricted/semantic/swap.cc b/yo/concrete/unrestricted/semantic/swap.cc new file mode 100644 index 00000000..d14602d6 --- /dev/null +++ b/yo/concrete/unrestricted/semantic/swap.cc @@ -0,0 +1,10 @@ +#include "semantic.ih" + +void Semantic::swap(Semantic &other) +{ + char buffer[sizeof(Semantic)]; + + memcpy(buffer, this, sizeof(Semantic)); + memcpy(this, &other, sizeof(Semantic)); + memcpy(&other, buffer, sizeof(Semantic)); +}