You are on page 1of 16

Role of data structure in compiler design

Mithiun kumar gupta


mithun_g013@yahoo.co.in

Reg. no. 11102557 Roll. No. RD1107A13

ABSTRACT:Most programmers write software in a high-level language, such as Pascal, C, C++, java, Cobol and others. Many are not aware of the fact that they are really making use of a sophisticated program called a compiler that bridges the gap between their chosen language and a computer

strategy used by a compiler helps the engineer understand the high-level language at a deeper level.

INTRODUCTION DESIGN

OF

COMPILER

A compiler is a computer program (or set of programs) that transforms source code written in a programming language (the source language) into another computer language (the target language, often having a binary form known as object code). The most common reason for wanting to transform source code is to create an executable program. The name "compiler" is primarily used for programs that translate source code from a high-level programming language to a lower level language (e.g., assembly language or machine code). If the compiled program can run on a computer whose CPU or operating system is different from the one on which the compiler runs, the compiler is known as across-compiler. A program that translates from a low level

architecture. Some have no concept at all, or a very poor grasp of the computer's instruction set, memory organization, and other details that make their software work. A compiler therefore provides a valuable form of information of hiding. translation Most and programmers don't need to know anything about the details execution, only the properties claimed to be supported by the high-level language and its libraries. Compilers design are a valuable and reliable tool for the most part, but no software is perfect. If a bug arises in code, it's sometimes useful to be able to trace it down into the assembler/micro instruction level. High performance may require certain low-level operations. Finally, knowing something about the

language to a higher level one is called a decompiles. A program that translates between high-level languages is usually called a language translator, source to source translator, or language converter. A language rewriter is usually a program that translates the form of expressions without a change of language. A compiler is likely to perform many or all of the following operations: lexical analysis, pre-processing, parsing, semantic optimization. Program faults caused by incorrect compiler behaviour can be very difficult to track down and work around; therefore, compiler implementers invest a lot of time ensuring the correctness of their software. Compiler design is focusing on more low-level and systems aspects rather than high-level questions such as polymorphic type inference or separate compilation. You will be building several complete culminating end-to-end in a compilers mildly for successively more complex languages, optimizing compiler for a safe variant of the C programming language to x86-64 assembly language. For the last project you will have the opportunity to optimize more aggressively, to implement a garbage analysis (Syntax-directed translation), code generating, and code

collector, or retarget the compiler to an abstract machine.

REQUIREMENT COMPILER DESIGN

OF

There are many requirement related to compiler as follow:CORRECTNESS:-

Correctness

is

absolutely

paramount. A buggy compiler is next to useless in practice. Since we cannot formally prove the correctness of your compilers, we use extensive testing. This testing is end-to-end, verifying the correctness of the generated code on sample inputs. We also verify that your compiler rejects programs as expected when the input is not well-formed (lexically, syntactically, or with respect to the static

semantics), and that the generated code raises an exception as expected if the language specification prescribes this. We go so far as to test that your generated code fails to terminate (with a time-out) when the source program should diverge. Emphasis on correctness means that we very carefully define the semantics of the source language. The semantics of the target language is given by the GNU assembler on the lab machines together with the semantics of the actually machine. Unlike C, we try to make sure that as little as possible about the source language remains undefined. EFFICIENCY: In a production compiler, efficiency of the generated code and also efficiency of the lax compiler targets itself for are important emphasizing considerations. In this course, we set very both, correctness instead. In one of the later labs in the course, you will have the opportunity to optimize the generated code. The early emphasis on correctness has consequences for your approach to the design of the implementation. Modularity and simplicity of the code are important for two reasons: first, your code is much more likely to be correct, and, second, you will be able to respond to changes in the source language specification from lab to lab much more easily. Retarget ability:At the outset, we think of a compiler of going from one source language to one target language. In practice, compilers may be required to Usability:A compiler interacts with the programmer primarily when there are errors in the program. As such, it should give helpful error messages. Also, compilers may be instructed to generate debug information together with executable code in order help users debug runtime errors in their program. In this course, we will not formally evaluate the quality or detail of your error messages, although you should strive to achieve at least a minimum standard so that you can use your own compiler effectively. INTEROPERABI LITY: Programs do not run in isolation, but are linked with library code before they are executed, or will be called as a library from other code. This puts some additional requirements on the compiler, which must respect certain interface specifications. This means that you will have to respect calling conventions early on (for example, properly save caller-save registers) and data layout conventions later, when code will be calling library functions.

generate more than one target from a given source (for example, x86-64 and ARM code), sometimes at very different levels of abstraction (for example, x86-64 assembly or LLVM intermediate code).

performed by collecting type information. The frontend then generates an intermediate representation or IR of the source code for processing by the middle-end. The middle end: -

THE STRUCTURE OF COMPILER DESIGN Compilers bridge source programs in high-level languages with the underlying hardware. A compiler requires;1) determining the correctness of the syntax of programs, 2) generating correct and efficient object code, 3) run-time organization, and 4) formatting output according to assembler and/or linker conventions. A compiler consists of three main parts: the frontend, the middle-end, and the backend. The front end: It checks whether the program is correctly written in terms of the and programming language syntax

It is indicate where optimization takes place. Typical transformations for optimization are removal of useless or unreachable code, discovery and propagation of constant values, relocation of computation to a less frequently executed place (e.g., out of a loop), or specialization of computation based on the context. The middle-end generates another IR for the following backend. Most optimization efforts are focused on this part. The back end:is responsible for

translating the IR from the middle-end into assembly code. The target instruction(s) are chosen for each IR instruction. Register allocation assigns processor registers for the program variables where possible. The backend utilizes the hardware by figuring out how to keep parallel execution units busy, filling delay slots, and so on. Although most algorithms for optimization are in NP, heuristic techniques are welldeveloped.

semantics. Here legal and illegal programs are recognized. Errors are reported, if any, in a useful way. Type checking is also

than one way, in the compile-time world, we have only recursion to do everything including looping; therefore, we are going to use recursion in the run-time version to compile Time Linked List If we are going to make a single linked list, then our structureof linked list would be something like this: /////////////////////////////////////////////////////////// // Node of Runtime Link List
Figure of structure of compiler design

///////////////////////////////////////////////////////////
struct ListNode { int value;ListNode* next; };

We have seen different applications of template meta-programming such as static data structures, algorithms, design patterns, Reflection, expression templates, and number theory. Compile Time Data Structure is, in fact, not a new concept in C++. Further information about it can be found in the References. Here, we are going to study the Linked List as an example of a compile time data structure, and will try to implement it with template metais programming. Template meta-programming usually difficult to understand at first, especially for those who are not familiar with it. Therefore, we will discuss the runtime counterpart at the same time. We use a naming convention List for all the runtime programs to distinguish it with the compile-time version. Although we can implement the run-time programs in more

Here is the compile time version of this structure: /////////////////////////////////////////////////////////// // Termination of Link List ///////////////////////////////////////////////////////////
struct End { };

/////////////////////////////////////////////////////////// // Node of Static Link List ///////////////////////////////////////////////////////////


template <int iData, typename Type> struct Node { enum { value = iData }; typedef Type Next;};

Here, we need one more structure to indicate the termination condition of the linked list. You can also call it is an end marker. In the runtime version, we dont need it because in that case, we simply

check the value of the next filed in the node. If its value is NULL, then it means that it is the last node of the linked list However, in the case of template meta-programming, we have to do template specialization (or partial template
}

if(*pHead==NULL) { *pHead = new ListNode(); (*pHead)->value = value; } Else { ListPushBack(&(*pHead)->next, value); }

specialization) to stop the recursion. We can do template specialization for any specific type or for any specific value. Here, we cant do template specialization on a value, because the second template parameter is a type. Therefore, we have to create a new type to stop the recursive instantiation of the template. The name of the end marker can be anything, and it can store whatever you like it to. In our example, it would be sufficient to make an empty structure to create a new type as an end marker. Now, lets try to implement a few auxiliary functions that work on lists. Here is our first function to insert data in the linked list. We explicitly made its name look similar to the member function of the STL list class, because we are going to implement a few more STL algorithms. Here is the simplest implementation for inserting items in the runtime single linked list. /////////////////////////////////////////////////////////// // Insert item into Runtime Link List ///////////////////////////////////////////////////////////
void ListPushBack(ListNode** pHead, int value) {

The name of the linked list is prefixed with List to distinguish it from the compile time version. Interestingly, the compile time version of the same function doesnt use recursion, and its implementation is very easy /////////////////////////////////////////////////////////// // Insert item into Static Link List ///////////////////////////////////////////////////////////
template <int iData, typename Type> struct PushBack { typedef Node<iData, Type> staticList; };

And, here is the usage of this function at compile time:


typedef PushBack<2, End>::staticList node1; typedef PushBack<4, node1>::staticList node2; typedef PushBack<6, node2>::staticList node3; typedef PushBack<8, node3>::staticList node4; typedef PushBack<10, node4>::staticList node5; typedef PushBack<12, node5>::staticList myList;

Although we can create a static linked list like this:


typedef Node<-15, Node<15, Node<18, Node<13, End> > > >myList;

the above method to create a static linked list has a few advantages, which we will see when we implement a few STL algorithms in the compile-time version. Now, lets implement a few more STL list algorithms at compile time. But, first take a look at its runtime version to better understand template metaprogramming. /////////////////////////////////////////////////////////// // Structure to calculate the length of Runtime Link List ///////////////////////////////////////////////////////////
int ListSize(ListNode* pHead) { if (pHead == NULL) return 0; else return 1 + ListSize(pHead->next); }

}; template <> struct Size<End> {enum { value = 0 }; };

Although the STL list class doesnt have an at() function, because list doesnt have a random access iterator, we are trying to implement this function for the linked list. Because we cant access any item of the linked list randomly, it is a linear time function, not a constant time one just like the at() function of the vector. Here is the simple run-time implementation of the at() function on a single linked list with linear complexity: /////////////////////////////////////////////////////////// // Structure to find item from specific location from RuntimeLink List ///////////////////////////////////////////////////////////
int ListAt(ListNode* pHead, int iPos) { static int iIndex = 0; ++iIndex; if (iIndex == iPos) return pHead->value; else if (pHead->next == NULL) return -1; else return ListAt(pHead->next, iPos); }

This function is quite simple, and uses tail recursion for optimization. The compiler can optimize tail recursion with looping to avoid any runtime stack overhead. Here is the compile-time version of the same function: /////////////////////////////////////////////////////////// // Structure to calculate the length of Static Link List ///////////////////////////////////////////////////////////
template <typename T> struct Size; template <int iData, typename Type> struct Size<Node<iData, Type> > { enum { value = 1 + Size<Type>::value };

The code presented here is just a proof of concept, not a production quality code. One major problem with this function is the return code. If the input position is greater than the length of the linked list,

like the length of the linked list is 4, but we are trying to access 6th element, then this function returns-1. This code is misleading, because -1 can be a data in the linked list at a given position, so it would be impossible to differentiate whether it is an error code or the actual data at the given position. This one is a much better implementation than the previous one: /////////////////////////////////////////////////////////// // Structure to find item from specific location from Runtime Link List ///////////////////////////////////////////////////////////
bool ListAt(ListNode* pHead, int iPos, int* iVal) { static int iIndex = 0; ++iIndex; if (iIndex == iPos) { *iVal = pHead->value;return true; } else if (pHead->next == NULL) {return false; } Else { return ListAt(pHead->next, iPos, iVal); } } {

int val; if (ListAt(pHead, 3, &mp;val)) {std::cout << val << std::endl;} }

Here is the compile time version of the same function: /////////////////////////////////////////////////////////// // Structure to find item from specific location from Static Link List ///////////////////////////////////////////////////////////
template <int iIndex, typename T, int iStart = 0>struct At; template <int iIndex, int iData, typename Type, int iStart>struct At<iIndex, Node<iData, Type>, iStart> { enum { value = iIndex == iStart ?iData : At<iIndex, Type, (iStart + 1)>::value }; }; template <int iIndex, int iData, int iStart>struct At<iIndex, Node<iData, End>, iStart> enum { value = iIndex == iStart ? iData : -1 }; };

This program has the same problem that it returns -1 when the item is not found. In template meta-programming, we cant return a value by parameter just like its runtime equivalent. The solution is to introduce one more enum variable inside

This function returns the value at a specific location by parameter. If the user passes a position that is greater than the length of the linked list, then it will return false; otherwise, it stores the value at the parameter and returns true. Here is the usage of this function:
if (pHead != NULL) {

the structure to store whether the item was found or not. Here is the next version of the same program: /////////////////////////////////////////////////////////// // Structure to find item from specific location from Static Link List ///////////////////////////////////////////////////////////
template <int iIndex, typename T, int iStart = 0>struct At;

template <int iIndex, int iData, typename Type, int iStart>struct At<iIndex, Node<iData, Type>, iStart> { enum { value = iIndex == iStart ?iData : At<iIndex, Type, (iStart + 1)>::value }; enum { found = iIndex == iStart ? 1 :At<iIndex, Type, (iStart + 1)>::found }; }; template <int iIndex, int iData, int iStart>struct At<iIndex, Node<iData, End>, iStart> { enum { value = iIndex == iStart ? iData : -1 }; enum { found = iIndex == iStart ? 1 : 0 }; };

The Find algorithm returns the first occurrence of the specified value in the given range. If it couldnt find the specified value, then it returns the end iterator, i.e., one past the last element given a range. Here is a simple usage of the Find algorithm onan STL list:
std::list<int>lst; lst.push_back(7); lst.push_back(14); lst.push_back(21); lst.push_back(28); lst.push_back(35);

Although the value variable still stores -1 when an item not found in the linked list, if we use the other variable, i.e., the found variable, then we can ignore this value. Here is the usage of this algorithm :
if (At<8, myList>::found == 1) { std::cout << At<8, myList>::value << std::endl; }

std::list<int>::iterator lst.end(), 7);

iter_

std::find(lst.begin(),

if (iter_ != lst.end()) std::cout << *iter_ << std::endl; else std::cout << "Not found" << std::endl;

Here is the closest implementation of the Find algorithm in template metaprogramming: /////////////////////////////////////////////////////////// // Structure to find the location of specific item in Static Link List ///////////////////////////////////////////////////////////
template <typename TBegin,typename TEnd,int

4. Compile Time Algorithms In this section, we are going to study different STL algorithms and their working with the STL list class, and how to implement those at compile time using template meta-programming. From now, instead of using creating our own single linked list and implementing all the related functions ourselves, we are going to use the STL list class. 4.1. Find Algorithm

iFindData,int iStart = 0>struct Find; template <int iData,typename TBegin,typename TEnd,int iFindData,int iStart> struct Find<Node<iData, TBegin>, TEnd, iFindData, iStart> { enum { value = iFindData == iData ? iStart :Find<TBegin, 1)>::value }; }; TEnd, iFindData, (iStart +

template <int iData,typename TEnd,int iFindData,int iStart> struct Find<Node<iData, TEnd>, TEnd, iFindData, iStart> { enum { value = iFindData == iData ? iStart : -1 }; }; template { enum { value = -1 }; }; <typename TEnd, int iFindData>struct Find<TEnd, TEnd, iFindData>

4.2. Count Algorithm This algorithm returns the numbers of items in a given range that has the given value. Here is a sample to demonstrate this:
std::list<int> lst;lst.push_back(7); lst.push_back(14);

This implementation returns the position of the specified value, if found in the given range of a single linked list; otherwise, it returns -1. Here is the usage of the above implementation:
typedef PushBack<7, End>::staticList node1; typedef PushBack<14, node1>::staticList node2; typedef PushBack<21, node2>::staticList node3; typedef PushBack<28, node3>::staticList node4; typedef PushBack<35, node4>::staticList myList;std::cout << Find<myList, End, 7>::value << std::endl;

lst.push_back(7); lst.push_back(14); lst.push_back(21); lst.push_back(7); std::cout << std::count(lst.begin(), lst.end(), 7) << std::endl;

The output of this program is 3, because 7 exists three times inthe given range. Here is a similar algorithm implemented atcompile time: /////////////////////////////////////////////////////////// // Count Algorithm. Returns the number of elements in StaticLink List ///////////////////////////////////////////////////////////
template <typename TBegin, typename TEnd, int iVal>struct Count; template <int iData, typename TBegin, typename TEnd, int iVal>struct Count<Node<iData, TBegin>, TEnd, iVal> { enum { value = (iData == iVal ? 1 : 0) + Count<TBegin, TEnd, iVal>::value }; }; template <int iData, typename TEnd, int iVal>struct Count<Node<iData, TEnd>, TEnd, iVal> {

We can even pass the range, just like in the STL algorithms, to find elements in between a given range.
std::cout << Find<node3, node1, 7>::value << std::endl;

This is one of the reasons to use the static version of the Push Back implementation rather than create a whole static linked list in one statement. By using the compile time version of the Push Back implementation, we are able to get the iterator equivalent in the compile time world.

enum { value = iData == iVal ? 1 : 0 }; }; template <typename TEnd, int iVal>struct Count<TEnd, TEnd, iVal> { enum { value = 0 }; };

in the given predicate. The predicate can be a simple function or a function object, i.e., a class with an overloaded () operator, that returns true. In that function (or function object), we can check any condition we want. Lets take a look at the run-time version to better understand it before going to the compile time version.
std::list<int>lst; lst.push_back(7); lst.push_back(14); lst.push_back(7); lst.push_back(14); lst.push_back(21); lst.push_back(7); std::list<int>::iterator =std::find_if(lst.begin(), lst.end(), MyPredicate()); if (iter_ != lst.end()) std::cout << *iter_ << std::endl; else std::cout << "Not found" << std::endl; iter_

This implementation is very similar to the Find algorithm, and its usage is also similar to that. Here is the closest implementation of the compile-time version of the same code we saw in this section using the STL count algorithm.
typedef PushBack<7, End>::staticList node1; typedef node2; typedef PushBack<7, node2>::staticList node3; typedef node4; typedef node5; typedef PushBack<7, node5>::staticList myList; std::cout << Count<myList, End, 7>::value << std::endl; PushBack<21, node4>::staticList PushBack<14, node3>::staticList PushBack<14, node1>::staticList

Here, we pass MyPridicate as a function Just like the Find algorithm, we object, and here is the implementation of it:
struct MyPredicate { bool operator()(int val) { return val > 10 && val < 20 ? true : false; } };

can also count the number of specified items in a given range rather than searching in the complete static linked list. 4.3. Find If Algorithm If we want to find whether a linked list contains an item that is greater than 10 but less than 20, then we couldnt do it with the Find algorithm. Here is the solution to this problem, the Find If algorithm. This algorithm returns the iterator of the element in the linked list that satisfies the condition

Implementing the compile time version of The Find If algorithm is not very difficult, and its looks very similar to the Find algorithm, except one addition to the predicate type parameter. Here is the compile algorithm: time version of theFind If

/////////////////////////////////////////////////////////// // Find If Algorithm. // Locate the specific items in Static Link List that satisfy thepredicate /////////////////////////////////////////////////////////// template <typename TBegin, typename TEnd, template <int iData> class Predicate, int iStart = 0> struct FindIf; template <int iData,typename TBegin, typename TEnd, template <int iData> class Predicate, int iStart> struct FindIf<Node<iData, TBegin>, TEnd, Predicate, iStart> { enum { value = Predicate<iData>::value == 1 ? iStart :FindIf<TBegin, TEnd, Predicate, (iStart+1)>::value }; }; template <int iData,typename TEnd, template <int iData> class Predicate,int iStart>struct TEnd, FindIf<Node<iData, Predicate, iStart> { enum { value = Predicate<iData>::value == 1 ? iStart : -1 }; }; template <typename TEnd, TEnd>,

template <int iData> class Predicate>struct FindIf<TEnd, TEnd, Predicate>


{enum { value = -1 }; };

Here we use template-template parameter to make it easy tocall and similar to STL algorithm. Here is the usage of this algorithm.
typedef PushBack<7, End>::staticList node1; typedef PushBack<14, node1>::staticList node2; typedef PushBack<7, node2>::staticList node3; typedef PushBack<14, node3>::staticList node4; typedef PushBack<21, node4>::staticList node5; typedef PushBack<7, node5>::staticList myList;std::cout << FindIf<myList, End, MyPredicate>::value <<std::endl;

In compile time world, the predicate is a structure (or class), not a function or function object. Here is our compile time version of the same predicate we used earlier in this section for the run time version:
template <int val>struct MyPredicate { enum { value = val > 10 && val < 20 ? 1 : 0 }; };

4.4. Count If Algorithm The Count if algorithm is a cousin of the Find If; the only difference is, it will return the number of elements in the linked list that satisfies the condition given in the predicate. Lets take a look at the run time version of this algorithm first.
std::list<int>lst; lst.push_back(7); lst.push_back(14); lst.push_back(7); lst.push_back(14); lst.push_back(21);

lst.push_back(7); std::cout << std::count_if(lst.begin(), lst.end(), MyPredicate())<< std::endl;

}; template <typename TEnd,template <int iData> class Prediate>struct CountIf<TEnd, TEnd, Prediate> {enum { value = 0 }; };

And, we use the same predicate that we made earlier:


struct MyPredicate{bool operator()(int val) { return val > 10 && val < 20 ? true : false; } };

This implementation is very similar to the Find If algorithm. The only difference is, here, we are actually count the number of elements that satisfy the condition given in the predicate rather than find it. Here is the usage of this algorithm:

The output of this program is 2, because there are two elements in the list which are greater than 10 and less than 20. Now, lets take a look at the compile time version of the same algorithm. /////////////////////////////////////////////////////////// // Count If Algorithm. // Returns the number of elements in Static Link List // that satisfy the predicate condition ///////////////////////////////////////////////////////////
template <typename TBegin, typename TEnd,template <int iData> class Predicate>struct CountIf; template <int iData, typename TBegin, typename TEnd,template { enum }; template <int iData, typename TEnd,template <int iData> class { enum { value = Predicate<iData>::value }; Predicate>struct CountIf<Node<iData, TEnd>, TEnd, Predicate> { value = (Predicate<iData>::value) +CountIf<TBegin, TEnd, Predicate>::value }; <int iData> class Predicate>struct CountIf<Node<iData, TBegin>, TEnd, Predicate> node4; node2;

typedef PushBack<7, End>::staticList node1; typedef PushBack<14, node1>::staticList

typedef PushBack<7, node2>::staticList node3; typedef typedef node5; typedef myList;std::cout PushBack<7, << node5>::staticList End, CountIf<myList, PushBack<14, PushBack<21, node3>::staticList node4>::staticList

MyPredicate>::value <<std::endl;

4.5. Min, Max Algorithm Although the STL version of the min and max algorithms dont work on a range, but for consistency, we implemented both algorithms in a similar way, i.e., you can find the maximum or minimum value in a static linked list in a given range. Here are the simple implementations of both the algorithms: /////////////////////////////////////////////////////////// // Structure to find the Maximum value in the Link List ///////////////////////////////////////////////////////////
template <typename TBegin, typename TEnd>struct Max;

template <int iData, typename TBegin, typename TEnd>struct Max<Node<iData, TBegin>, TEnd > { enum { value = iData > Max<TBegin, TEnd>::value ? iData : Max<TBegin, TEnd>::value }; }; template { enum { value = iData }; }; <int iData, typename TEnd>struct Max<Node<iData, TEnd>, TEnd>

maximum and minimum values in the static linked list, respectively. Just like the other algorithms, here, we can also specify the range to get the maximum or minimum value in a given range, not in the complete static linked list. 4.6. For Each Algorithm Till now, all the algorithms we discussed were just getting information from the linked list. None of the above algorithms changed any values in the linked list. This is because once you have some value, then it is very difficult, if not impossible, to change the value we assigned at compile time. Now, we are going to discuss an algorithm that performs some operation on the values of the linked list, but here, we explicitly restrict ourselves to not change any value in the linked list. Lets take a look at this simple example of the For Each algorithm to print the elements of the linked list:
std::for_each(lst.begin(), lst.end(),PrintFunctionObject()); Here, PrintFunctionObject is our function object to do the actual work. Here is a simple implementation of this predicate: struct PrintFunctionObject { void operator()(int val) {std::cout << val << std::endl;} };

/////////////////////////////////////////////////////////// // Structure to find the Minimum value in the Link List ///////////////////////////////////////////////////////////
template <typename TBegin, typename TEnd>struct Min; template <int iData, typename TBegin, typename TEnd>struct Min<Node<iData, TBegin>, TEnd> { enum { value = iData < Min<TBegin, TEnd>::value ? iData : Min<TBegin, TEnd>::value }; }; template { enum { value = iData }; }; <int iData, typename TEnd>struct Min<Node<iData, TEnd>, TEnd>

And, here is a simple usage of these algorithms:


std::cout << Max<myList, End>::value << std::endl; std::cout << Min<myList, End>::value << std::endl;

If we use the same static linked list that we created in the previous section, then we will get 21 and 7 as the output as the

Remember, it can also be a simple function instead of a function object. Here is the compile time equivalent version of the same algorithm:

/////////////////////////////////////////////////////////// // For each algorithm. Apply some action on all items of the list ///////////////////////////////////////////////////////////
template <typename TBegin, typename TEnd,template <typename T> class Function>struct ForEach; template <int iData, typename TBegin, typename TEnd,template <typename T> class Function>struct ForEach<Node<iData, TBegin>, TEnd, Function> { void operator ()() { Function<TBegin>()(iData); ForEach<TBegin, TEnd, Function>()(); } }; template <int iData, typename TEnd,template <typename T> class Function>struct ForEach<Node<iData, TEnd>, TEnd, Function> { void operator ()(){Function<TEnd>()(iData); } }; template <typename TEnd,template <typename T> class Function>struct ForEach<TEnd, TEnd, Function> {void operator ()(){} };

and compile-time programming. All of the programs we discussed earlier were completely resolved by the compiler at the time of compiling and the actual result stored in the executable. However, in this case, although we are doing compile time computation during compilation using Recursion, the actual function call will still execute when you run this program. This is the only way to perform some IO operations while doing template metaprogramming, i.e., using functions that will execute at runtime. Here, we are not only limited to performing IO operations but can do a few more interesting things, like create a class using the new operator or a set of class hierarchies, as described in Modern C++ Design[1]. Here is the function object for this compile time implementation of the For Each algorithm.
template PrintFunctonObject { <typename T>struct

If you have taken a close look at this implementation, then you may have already noticed that this implementation is quite different from all of those we discussed earlier. In this implementation, there isnt any enum variable; on the contrary, here we have the overload () operator. This is because when we have to perform some action, we have to call some function to do the actual work. This program is actually a mixture of run-time

void operator ()(int iData) {std::cout << iData << std::endl;} };

The usage of this algorithm is also slightly different. Here, we actually want to execute some code at run-time; therefore, we have to create an object of the ForEach structure. Here is one possible way to execute this algorithm using an anonymous object:

ACKNOWLEGEMENT Firstly I want to say to thanks of my subject teacher and education management, because they think able me of this topic of term paper and give the golden opportunity to prepare of term paper. M y term paper topic is Role of (4) Modern C++ Programming. Design Generic D a t a Structure in Compiler Design. This topic is related to my subject Data Structure; this topic help know how can compile the softwares. This topic is clear my more concept. I wish to express to my gratitude to all the people involved in the writing of this project, specially Sandeep Sharma sir who was very generous in sharing their time and knowledge with me. I thank to LPU Wi-Fi; they are give fully support. REFERENCES:
(1) http://www.engr.sjsu.edu/wbarrett/P (5) C++ Template Metaprogramming: (3) http://en.wikipedia.org/wiki/Compil (2) http://www.capsl.udel.edu/conferen

ces/open64/2008/Papers/111.pdf

er

Concepts.
(6) Reflection support by means of

template Guiseppe Cisternino

Meta-programming, Attardi, Antonio

(7) Static Data Structure: Reconciling

Template Meta-programming and Generic Programming.


(8) Loops, Metaloops & C++, Roshan

arser/CompDesign.pdf

Naik.6. Expression Templates, Veldhuizen, C++ Report 1995,Generative Programming Methods, Tools and Applications7. Template Meta Programm

You might also like