mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-11-16 07:48:44 +01:00
WIP concrete/unrestricted with Bisonc++
git-svn-id: https://cppannotations.svn.sourceforge.net/svnroot/cppannotations/trunk@615 f6dd340e-d3f9-0310-b409-bdd246841980
This commit is contained in:
parent
3ab434a93e
commit
3c45354ff5
25 changed files with 557 additions and 11 deletions
99
yo/advancedtemplates/aliases.yo
Normal file
99
yo/advancedtemplates/aliases.yo
Normal file
|
@ -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 <typename T> struct X {...};
|
||||
|
||||
template <typename T>
|
||||
using VecT = vector<T, Alloc<T>>;
|
||||
|
||||
Vec<int> vi; // same as vector<int, Alloc<int>> 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<class T>
|
||||
using Vec = std::vector<T,My_alloc<T>>; // standard vector using my allocator
|
||||
|
||||
Vec<int> fib = { 1, 2, 3, 5, 8, 13 }; // allocates elements using My_alloc
|
||||
|
||||
vector<int,My_alloc<int>> 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<int>
|
||||
struct int_exact_traits { // idea: int_exact_trait<N>::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<int N>
|
||||
using int_exact = typename int_exact_traits<N>::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 <typename T>
|
||||
using Dictionary = std::map< std::string, T >;
|
||||
|
||||
Dictionary<int> ints;
|
||||
ints[ "one" ] = 1;
|
||||
ints[ "two" ] = 2;
|
||||
|
||||
---------------------- the really useful case:
|
||||
|
||||
#include <vector>
|
||||
|
||||
template <typename Type, template <typename> class Container>
|
||||
struct Wrapper: public Container<Type>
|
||||
{};
|
||||
|
||||
template <typename Type>
|
||||
using VT = std::vector<Type>;
|
||||
|
||||
int main()
|
||||
{
|
||||
Wrapper<int, VT> wi;
|
||||
// Wrapper<int, std::vector> wi2; ERR!
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
15
yo/concrete/unrestricted.yo
Normal file
15
yo/concrete/unrestricted.yo
Normal file
|
@ -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)
|
1
yo/concrete/unrestricted/CLASSES
Normal file
1
yo/concrete/unrestricted/CLASSES
Normal file
|
@ -0,0 +1 @@
|
|||
semantic
|
112
yo/concrete/unrestricted/icmconf
Normal file
112
yo/concrete/unrestricted/icmconf
Normal file
|
@ -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"
|
4
yo/concrete/unrestricted/input
Normal file
4
yo/concrete/unrestricted/input
Normal file
|
@ -0,0 +1,4 @@
|
|||
abc(def);
|
||||
xyz = 5;
|
||||
|
||||
|
12
yo/concrete/unrestricted/main.cc
Normal file
12
yo/concrete/unrestricted/main.cc
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "main.ih"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Parser parser;
|
||||
|
||||
parser.setDebug(argc == 1);
|
||||
|
||||
parser.parse();
|
||||
|
||||
return 0;
|
||||
}
|
6
yo/concrete/unrestricted/main.ih
Normal file
6
yo/concrete/unrestricted/main.ih
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "parser/preinclude.h"
|
||||
#include "parser/parser.h"
|
33
yo/concrete/unrestricted/parser/grammar
Normal file
33
yo/concrete/unrestricted/parser/grammar
Normal file
|
@ -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';
|
||||
}
|
||||
;
|
||||
|
53
yo/concrete/unrestricted/parser/parser.h
Normal file
53
yo/concrete/unrestricted/parser/parser.h
Normal file
|
@ -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
|
6
yo/concrete/unrestricted/parser/parser.ih
Normal file
6
yo/concrete/unrestricted/parser/parser.ih
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Include this file in the sources of the class Parser.
|
||||
|
||||
// $insert class.h
|
||||
#include "parser.h"
|
||||
|
||||
using namespace std;
|
6
yo/concrete/unrestricted/parser/preinclude.h
Normal file
6
yo/concrete/unrestricted/parser/preinclude.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef INCLUDED_PREINCLUDE_H_
|
||||
#define INCLUDED_PREINCLUDE_H_
|
||||
|
||||
#include "../semantic/semantic.h"
|
||||
|
||||
#endif
|
34
yo/concrete/unrestricted/scanner/lexer
Normal file
34
yo/concrete/unrestricted/scanner/lexer
Normal file
|
@ -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];
|
||||
|
||||
|
||||
%%
|
||||
|
||||
|
||||
|
25
yo/concrete/unrestricted/scanner/scanner.h
Normal file
25
yo/concrete/unrestricted/scanner/scanner.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef SCANNER_H_
|
||||
#define SCANNER_H_
|
||||
|
||||
#include "../semantic/semantic.h"
|
||||
|
||||
#if ! defined(SKIP_FLEXLEXER_) && ! defined(SYSINC_FLEXLEXER_H_)
|
||||
#include <FlexLexer.h>
|
||||
#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
|
30
yo/concrete/unrestricted/scanner/scanner.ih
Normal file
30
yo/concrete/unrestricted/scanner/scanner.ih
Normal file
|
@ -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 <iostream>
|
||||
// #include <fstream>
|
||||
// #include <strstream>
|
||||
// #include <string>
|
||||
|
||||
/*
|
||||
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
|
7
yo/concrete/unrestricted/semantic/destructor.cc
Normal file
7
yo/concrete/unrestricted/semantic/destructor.cc
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "semantic.ih"
|
||||
|
||||
Semantic::~Semantic()
|
||||
{
|
||||
if (d_int.first == IDENTIFIER)
|
||||
d_str.second.~string(); // destroy the string's memory
|
||||
}
|
5
yo/concrete/unrestricted/semantic/frame
Normal file
5
yo/concrete/unrestricted/semantic/frame
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include "semantic.ih"
|
||||
|
||||
Semantic::
|
||||
{
|
||||
}
|
8
yo/concrete/unrestricted/semantic/operatorassign.cc
Normal file
8
yo/concrete/unrestricted/semantic/operatorassign.cc
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include "semantic.ih"
|
||||
|
||||
Semantic &Semantic::operator=(Semantic const &rhs)
|
||||
{
|
||||
Semantic tmp(rhs);
|
||||
swap(tmp);
|
||||
return *this;
|
||||
}
|
15
yo/concrete/unrestricted/semantic/operatorinsert.cc
Normal file
15
yo/concrete/unrestricted/semantic/operatorinsert.cc
Normal file
|
@ -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*>";
|
||||
}
|
38
yo/concrete/unrestricted/semantic/semantic.h
Normal file
38
yo/concrete/unrestricted/semantic/semantic.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef INCLUDED_SEMANTIC_
|
||||
#define INCLUDED_SEMANTIC_
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
union Semantic
|
||||
{
|
||||
friend std::ostream &operator<<(std::ostream &out, Semantic const &obj);
|
||||
|
||||
std::pair<int, int> d_int;
|
||||
std::pair<int, std::string> 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
|
6
yo/concrete/unrestricted/semantic/semantic.ih
Normal file
6
yo/concrete/unrestricted/semantic/semantic.ih
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include "semantic.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
14
yo/concrete/unrestricted/semantic/semantic1.cc
Normal file
14
yo/concrete/unrestricted/semantic/semantic1.cc
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include "semantic.ih"
|
||||
|
||||
Semantic::Semantic(Type type, char const *txt)
|
||||
{
|
||||
d_int.first = static_cast<int>(type);
|
||||
|
||||
if (type == IDENTIFIER)
|
||||
new (&d_str.second) string(txt);
|
||||
else
|
||||
{
|
||||
istringstream in(txt);
|
||||
in >> d_int.second;
|
||||
}
|
||||
}
|
9
yo/concrete/unrestricted/semantic/semantic2.cc
Normal file
9
yo/concrete/unrestricted/semantic/semantic2.cc
Normal file
|
@ -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);
|
||||
}
|
10
yo/concrete/unrestricted/semantic/swap.cc
Normal file
10
yo/concrete/unrestricted/semantic/swap.cc
Normal file
|
@ -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));
|
||||
}
|
Loading…
Reference in a new issue