Macro Processor
Macro Processor
Macro Processor
Very often we need short-cuts to get things done fast and to avoid confusion, and
that is the exact requirement of the programming world. Today, as programming languages grow
more sophisticated and make the life of a programmer easier, the requirements keep growing.
Programming languages perform Herculean tasks as compared to their ancestors several decades
ago. For example, from the simple days of C, companies such as Microsoft have developed much
more powerful languages such as Visual C#, which has the simplicity and foundation of C. Yet,
as we progress with the use of these languages, there are still some tools that are in use today that
make processing of code much simpler.
Code grows to such an extent today that even code needs management and
processing. In this project, we look at the processing of code before it is sent for compilation.
These tasks are called pre-processor tasks, where code is “prepared” before it is sent for
compilation. These are also known as pre-processor directives which perform a task before the
code is compiled. There are many such tools, including macro expansions. Macros are used to
make compilation easier and more feasible. We can look at the various advantages macros give
the programmer as we look at the problems inherent with coding. It should also be noted that the
subject of macros are vast and that only a few macros will be simulated. To a large extent,
macros will be designed to mimic C macros.
A macro is a piece of code or text that replaces another body of text before
compilation. These macros may or may not take parameters. In C#/C++, macros are preceded
with the “#” keyword. Therefore, code is scanned and those lines starting with the “#” symbol
are treated first and the appropriate action performed. These lines with “#” preceding them are
removed and that edited code is sent for compilation. Any compilation errors caused by macro
expansions have to be taken care of by the user. Macros can be used in a simple or complex way
to make effective use of code. A very good example is described below:
(iv)
gotoxy(10,3); //position cursor at x-axis 3 and y-axis 10
printf(“Code printed here”); //default printing function
Here, DIS(3,10) is replaced with “gotoxy(10,3); printf” in the original source code before it is
sent for compilation. Therefore, this becomes easier if the programmer requires constant re-
positioning of cursor. The code is effectively shorter to type and much easier to read when there
are many such statements. It also becomes easier for programmers to give coordinates who are
used to providing x-asks co-ordinates first.
This is how normal macros that accept parameters work in C. These macros will be simulated in
this project.
(v)
Table of Contents
Acknowledgements iii
Abstract iv
1. Introduction
1.1. Detailed Problem Definition 2
1.2. Block Diagram 4
2. Analysis
2.1. Domain Theory of the Problem 6
2.2. SS Concept used 7
2.3. Hardware and Software Requirements 9
2.4. Description of tools used 9
3. System Design
3.1. Modular Design 11
3.2. Detail for each Module 13
3.3. Input Specifications 17
3.4. Output Specifications 17
4. Implementation
4.1. Screen Shots 22
4.2. Sample Code 26
5. Testing
5.1. Test Cases 44
5.2. Test Reports 45
6. Conclusion
6.1. Advantages and Disadvantages 48
6.2. Future Enhancements 49
References
Appendix A (Macros) 51
Appendix B (C# Programming) 62
Bibliography 65
Macro Processor for C/C++
Chapter – 1
INTRODUCTION
Processing of source code for a compiler requires many tasks before actual
compilation of the program. Most of theses tasks require refinement of code for the
machine to understand. Programmers may write code to the best possible extent of their
understanding and simplicity. Therefore, this requires a translation to more extensive
code that the compiler can understand. Some of the problems faced by programmers in
writing extensive code are explained in detail in the next few paragraphs.
Code Readability: Very often while writing large chunks of code, there may be many
places where code is repeated. Repetition of code can lead to confusion and reduce the
readability of code. Maintaining readability is one of the main essences of proper
programming. It also is the most difficult of tasks. Even with sufficient comments and
spacing, it can still be hard to maintain readability. Furthermore, it is hard for humans to
understand the same level of instructions as programming languages. The balance
between human understanding and mnemonics is often blurred. It would be feasible for
the programmer to replace large chunks of repeated code with a single “code” that has the
same meaning. This would improve readability to a great extent and help with debugging
purposes too. However, replacement text can sometimes cause more confusion if the
programmer does not properly handle them.
Function Overhead: Functions help solve this problem by sorting relevant code into
one area. A program in sequence can call such a function, make it perform its task and
return control to the line following the function call. However, functions (or methods)
have a large overhead and can waste valuable processor time by repeatedly calling the
same function. In fact there is nothing wrong with repeated code for the compiler. If the
program execution requires repeated execution of codes, then functions will cause a
Increased Processor Time: As already mentioned, repeated codes and calls for
replacement can cause considerable processor wastage. Processing time is an important
component of any system software. Applications can afford to suffer from processing
time, but if system software largely suffers from processing time, then the whole setup is
affected. Macros may increase compilation time by replacing text, including more text
and submitting partial parts for compilation, but they help in producing more reliable
code.
Increased Spaghetti Code: The use of functions and redirection of control to other
places to perform repeated functions results in what is called “spaghetti code”. This kind
of code is rampant in the older top-bottom approach of programming languages, where
instructions appear in sequence. Object-oriented programming techniques remove
spaghetti code problems, but can only be implemented on object-oriented platforms.
Moreover, even OOP concepts still suffer from readability problems. Programming
languages such as C, where spaghetti code is all but common; macros can help reduce
this problem
The following is a block representation of the various actions that will take
place for a fully-processed file with macros expanded and removed.
Input file
Processed
file
Fig
1.a. Block representation of macro expansion
Chapter – 2
ANALYSIS
Macros
A macro, as already mentioned, is an abbreviation for a sequence of
operations. Macros are used to replace text and help solve problems such as readability
and simplicity. In primitive assembly code, macros are defined by two instructions the
MACRO and MEND instruction. A macro operation permits writing a sequence of
assembly instructions and to using its name in to replace it. A macro processor is by itself
a language processor with its own syntax and rules. The general form of writing a macro
in assembly language is
MACRO <macro-name>
//Body of the macro
MEND
Macros can do more than just replace text where it is required. Some of the
additional features of macros are as follows:
9 Macros can take parameters whose values can be replaced within the macro
expansion. This makes macro usage more dynamic
9 Macros can be used to conditionally include code depending on some condition.
This is useful for codes which may vary on different architectures.
9 Macros that exist within a macro (recursive calls of macros)
Lexical Analyser
Although this is not part of the scope of the project, it was required here
and there to understand the boundary of the macro calls. It was important to know the
sequence of tokens to know when a macro may start and end. To limit the use of lexical
analysing concepts, macro calls in the main source code are surrounded by user-defined
characters such as ‘@’. Therefore, a complete and exact simulation of macro calls in
C#/C++ was not possible as the realm of lexical analysis was necessary to achieve this
task.
Hardware Requirements
9 Pentium 60 MHz or higher
9 8 MB RAM or higher
9 10 MB hard-disk space free (not including swap space required for the OS)
Software Requirements
9 Borland Turbo C compiler or any other version compatible with IO streams
9 Windows 98 or later
9 Implementable on UNIX OS with minor adjustments
Microsoft Visual C#.Net is used for developing front end for this project. C# is a multi-
paradigm programming language encompassing imperative, functional, generic, object-
oriented (class-based), and component-oriented programming disciplines. It was
developed by Microsoft within the .NET initiative and later approved as a standard by
Ecma (ECMA-334) and ISO (ISO/IEC 23270). C# is one of the programming languages
designed for the Common Language Infrastructure.
Chapter – 3
SYSTEM DESIGN
The project is largely divided into two major modules. The logic followed
is that of a two-pass processor. The first pass scans for macros and makes an entry of
macros found that will be found in the main source code. The second pass scans for
replacement of macros in the main source code. Within these modules, it can be further
broken down to smaller modules for better understanding and refinement.
First Pass
The first pass, as already stated carries out the scanning of macros.
Algorithm 3.2 (a) shows the overall working of this module. There are a lot more cases
and validations that occur in this module than that depicted in figure 3.2.(a). The kind of
macros used here are simple, one-line macros that have their beginning indication with
the symbol ‘#’ and the termination with the newline character ‘\n’. Therefore, if a
newline is encountered before the macro name and definition, then the macro has pre-
maturely ended. Such encounters should not stop the pre-processing work, but merely
highlight the programmer that there are errors with macro declarations. Errors which are
overlooked are taken care of in the next pass. The first pass module has the following
features:
Error-checking: Errors are highlighted to the programmer when required, else rectified
as much as possible. For example, whitespaces are generally never considered as part of
the compilation routine. Therefore, the following routine is followed:
# <macro-directive> <macro-name> <macro-definition> ¬
File Preparation: Macros are found and reported as successful and the input program is
stored into a different files without the macros. The macro names and the definitions are
stored in a structure. As error-checking continues, two variables that hold the values for
Department of Computer Science (MCA), Christ University 11
Macro Processor for C/C++
the macro name and macro definition. Files are a better option as the number of macros
might be large. Arrays would not be suitable to hold these values as handling character
arrays in C are highly sensitive and resource-consuming. Therefore, entries for macros
should not be written to files, if there are any errors during the scanning of that particular
macro.
Second Pass
The second pass is concerned with replacing macros and removing their
definitions as they are not tokens that do not make sense to the compiler. Algorithm 3.2
(b). gives an idea of the working of this module. However, there are more background
processes that run, which complete the process of replacing macros and preparing the
final source code. The second pass module has the following features:
Scanning for keywords: For the design of macro processor in this project, there are two
keywords that require actions to be performed. The first keyword is the ‘#’ symbol. This
symbol can mean two things—a macro definition or a conditional macro directive.
Therefore, the macro directive following the ‘#’ symbol should be scanned to determine
what action is to be performed.
Macro Expansion: This is the obvious part of the pre-processing task. Since the macro
names and the corresponding macro definitions are stored in the structure the expansion
is just replacing the macro names with its definition. If no macro name exists for the
keyword found, then the error should be highlighted and the text should be maintained as
it is. If the macro name is invalid, then it is possible that text woulds require being output
Department of Computer Science (MCA), Christ University 12
Macro Processor for C/C++
as it is. This can happen in printf statements. However, if the macro name does exist, the
corresponding definition should be replaced as it is.
File Preparation: In the end, the output of the program should be a C file that is ready
for compilation. The final file should be free of all macro directives such as the ‘#’
symbol. Most importantly, is that all handlers and resources should be released. The new
file created should have the extension .c.
• Save a copy of the input text, minus macro definitions on secondary storage for
use in pass II
Pass II
• Replace each macro name with the appropriate text from the macro definition.
Else
Copy to destination file + Break character.
4. ALA (Argument List Array), to substitute index markers for dummy args. Before
storing the macro def.
Pass 2:.
3. ALA ( Argument List Array), to substitute macro call arguments for the index
markers in the stored macro definition.
¾ The macro name table is used to store the information related to macro.
¾ Macro type is found i.e. either object type(o) or function type(f) and is added to
MNT .
¾ The macro definition table is used to store the body of each macro defined.
¾ When the macro definition (#define) is found during scanning, the respective body
of the macro defined is stored in MDT.
¾ This macro definition table is also referred when a macro call is encountered.
During this the body of the macro is obtained from MDT and is expanded.
When the macro body is added to the MDT, during that time, if argument is
present, then it is replaced by its index prefixed with # (eg. #1 represents 1st
argument).
¾ During macro call- when macro with arguments is called then all the arguments
are put to the ARGT in the sequence they appear.
When the macro body is added to the MDT, during that time, if positional
parameters (e.g. #1) are obtained then they are replaced using ARGT.
Chapter – 4
IMPLEMENTATION
str = null;
argt.Clear();
str1 = null;
temp = null;
temp1 = null;
str = sourcesr.ReadLine();
if (str == "")
continue;
temp = str;
SourceCode.Items.Add(str);
if (temp[0] == '#' && temp[1] == 'd' && temp[2] == 'e' && temp[3] == 'f' && temp[4]
== 'i' && temp[5] == 'n' && temp[6] == 'e')
{
temp1 += temp[j];
}
for (; temp[j].ToString() != " " && temp[j].ToString() != "("; j++)
{
str1 += temp[j];
}
name = str1;
macroflag = 1;
macrolist.Items.Add(str1);
if (temp[j].ToString() == " ")
{
type = "O";
acount = 0;
start = mdtc + 1;
do
{
str1 = null;
for (; j < temp.Length && temp[j].ToString() != "\\"; j++)
{
str1 += temp[j];
}
mdtc = mdtc + 1;
mdt.Rows.Add(mdtc, str1.Trim());
if (j < temp.Length)
{
temp = null;
temp = sourcesr.ReadLine();
SourceCode.Items.Add(temp);
j = 0;
}
} while (j == 0);
}
else if (temp[j].ToString() == "(")
{
acount = 0;
type = "F";
j++;
start = mdtc + 1;
str = null;
if (temp[j].ToString() != ")")
{
while (temp[j - 1].ToString() != ")")
{
if (temp[j].ToString() == "," || temp[j].ToString() == ")")
{
if (str.Trim() != "")
{
argtf = 1;
argtc = argtc + 1;
argt.Add(argtc, str);
str = null;
acount = acount + 1;
}
}
else
{
str1 = null;
for (; j < temp.Length && temp[j].ToString() != "\\"; j++)
{
str1 += temp[j];
}
if (argtf == 1)
{
temp1 = null;
temp1 = str1.Trim() + "\\";
str1 = null;
str = null;
for (k = 0; k < temp1.Length; k++)
{
if (argt.ContainsValue(str) == true)
{
}
else
{
str += temp1[k];
}
}
mdtc = mdtc + 1;
mdt.Rows.Add(mdtc, str1.Trim(' ', '\\'));
if (j < temp.Length)
{
temp = null;
temp = sourcesr.ReadLine();
SourceCode.Items.Add(temp);
temp = temp.Trim();
j = 0;
}
} while (j == 0);
}
mntc = mntc + 1;
mnt.Rows.Add(mntc, name, type, start, mdtc, acount);
}
}
}
Com_module.ff.dataGridView1.DataSource = mdt;
Com_module.ff1.dataGridView1.DataSource = mnt;
if (macroflag == 1)
{
stringiflag = 0;
FileStream fs2 = new FileStream(filetext.Text, FileMode.Open, FileAccess.Read);
}
else
{
j = 0;
key = 0;
temp = str;
str1 = null;
str = null;
//richTextBox1.Select(richTextBox1.SelectionStart, str.Length);
//MessageBox.Show(richTextBox1.SelectionStart.ToString() );
//MessageBox.Show(richTextBox1.SelectionLength.ToString());
richTextBox1.SelectionColor = Color.BlueViolet;
}
}
while (temp[k - 1] != ')')
{
k = k + 1;
}
if (acount == 0)
{
str = null;
for (j = mdtps - 1; j <= mdtpe - 1; j++)
{
str = null;
if (j > mdtps - 1)
{
richTextBox1.Text = richTextBox1.Text + "\n";
//richTextBox1.Select(richTextBox1.SelectionStart, str.Length);
//MessageBox.Show(richTextBox1.SelectionStart.ToString() );
//MessageBox.Show(richTextBox1.SelectionLength.ToString());
richTextBox1.SelectionColor = Color.BlueViolet;
}
}
else
{
str = null;
stringiflag = 0;
for (j = mdtps - 1; j <= mdtpe - 1; j++)
{
str1 = null;
fstr = null;
str = null;
if (j > mdtps - 1)
{
richTextBox1.Text = richTextBox1.Text + "\n";
}
pp = int.Parse(fstr);
if (stringiflag == 0)
{
}
else
{
if (sst + 1 < str11.Length && str11[sst + 1].ToString()
== "\"")
}
else
{
strs = strs + str11[sst];
}
}
}
strs = "\"" + strs + "\"";
str1 = str1 + strs;
//str1 = str1 + "\"" + argt[pp - 1].ToString() + "\"";
}
}
else
{
str1 = str1 + str[ii];
}
}
}
else
{
richTextBox1.Text = richTextBox1.Text + str + temp[k].ToString();
}
//str1 = str1 + str + temp[k].ToString();
str = null;
}
else
{
str = str + temp[k].ToString();
}
}
// richTextBox1.Text = richTextBox1.Text + str1+"\n";
richTextBox1.Text = richTextBox1.Text + "\n";
Chapter – 5
TESTING
The following test plans were put into effect and carried out:
Basic Validation: This requires that the input file exist before being processed. The
name of the file is input is given as a parameter with the execution of the program. If the
filename provided as input is invalid or doesn’t exist in the current directory, the program
terminates and reports that the file doesn’t exist or cannot be opened.
Names of Directives: For macro saving, only #define macros are taken care of. The
other macros are seen as errors for the first pass, but may be valid for the next pass. The
Chapter – 6
CONCLUSION
9 Effectively replaces code that was meant for replacement with the help of macros.
9 Used concepts such as file pointers, structures to carry out its tasks
9 Highlights errors caused by macros that the programmer can rectify before the
code is sent for compilation rather than to be intimated of errors during
compilation.
9 Produces the output file, even if there are errors or warnings in the input file.
9 Maintains a separate input file and a separate output file for data verification and
rectification.
9 Maintains macro names and their definitions in structures, thereby reducing the
amount of resources involved with character arrays and is useful for debugging
purposes.
9 Tabs and whitespaces and original contents of the input file are maintained as they
are even in the final source code file.
x Conditional macros are not taken care only simple macros, parameterized macro,
macro within macros are taken care off.
x The input file has to be prepared as a text file, which means the programmer will
have to first save his program as a .txt file. Also, the output file is created as a .txt
file, which means the programmer will have to bring this output file back to the
IDE for compilation. Compilation errors would require the programmer to start the
process from scratch
Inclusion of a compiler
Steps can be taken to develop an IDE (Integrated Development
Environment), so that the output cpp file can be directly compiled and the results caused
due to macro expansions can be taken care of. However, the development of an IDE
would require also the development of an editor, a parser, linker and other systems
software concepts that are well beyond the boundaries of a simple macro processor.
However, with the combination of a compiler, the use of macros can be fully justified.
User-defined macros
User-defined macros can be setup to help programmers work with arrays
and files better. These macros can be used to perform regular tasks such as arranging
elements in ascending or descending order, or to open files with a given filename and file
mode. These specifics can be applied with more input from the programmer as to how he
would like to lessen the amount of typing and to help increase readability.
REFERENCES
Appendix A (Macros)
Macros
A macro is a sort of abbreviation which you can define once and then use later. There are
many complicated features associated with macros in the C preprocessor.
Simple Macros
Before you can use a macro, you must define it explicitly with the `#define' command.
`#define' is followed by the name of the macro and then the code it should be an
abbreviation for. For example,
A simple macro always stands for exactly the same text, each time it is used. Macros can
be more flexible when they accept arguments. Arguments are fragments of code that you
supply each time the macro is used. These fragments are included in the expansion of the
macro according to the directions in the macro definition.
To define a macro that uses arguments, you write a `#define' command with a list of
argument names in parentheses after the name of the macro. The argument names may be
For example, here is a macro that computes the minimum of two numeric values, as it is
defined in many C programs:
(This is not the best way to define a "minimum" macro in GNU C. See section
Duplication of Side Effects, for more information.)
To use a macro that expects arguments, you write the name of the macro followed by a
list of actual arguments in parentheses, separated by commas. The number of actual
arguments you give must match the number of arguments the macro expects. Examples
of use of the macro `min' include `min (1, 2)' and `min (x + 28, *p)'.
The expansion text of the macro depends on the arguments you use. Each of the argument
names of the macro is replaced, throughout the macro definition, with the corresponding
actual argument. Using the same macro `min' defined above, `min (1, 2)' expands into
where `1' has been substituted for `X' and `2' for `Y'.
Parentheses in the actual arguments must balance; a comma within parentheses does not
end an argument. However, there is no requirement for brackets or braces to balance, and
they do not prevent a comma from separating arguments. Thus,
After the actual arguments are substituted into the macro body, the entire result is
appended to the front of the remaining input, and the check for macro calls continues.
Therefore, the actual arguments can contain calls to other macros, either with or without
arguments, or even to the same macro. The macro body can also contain calls to other
macros. For example, `min (min (a, b), c)' expands into this text:
(Line breaks shown here for clarity would not actually be generated.)
If a macro foo takes one argument, and you want to supply an empty argument, you must
write at least some whitespace between the parentheses, like this: `foo ( )'. Just `foo ()' is
providing no arguments, which is an error if foo expects an argument. But `foo0 ()' is the
correct way to call a macro defined to take zero arguments, like this:
If you use the macro name followed by something other than an open-parenthesis (after
ignoring any spaces, tabs and comments that follow), it is not a call to the macro, and the
preprocessor does not change what you have written. Therefore, it is possible for the
same name to be a variable or function in your program as well as a macro, and you can
choose in each instance whether to refer to the macro (if an actual argument list follows)
or the variable or function (if an argument list does not follow).
You may not define the same name as both a simple macro and a macro with arguments.
In the definition of a macro with arguments, the list of argument names must follow the
macro name immediately with no space in between. If there is a space after the macro
name, the macro is defined as taking no arguments, and all the rest of the line is taken to
be the expansion. The reason for this is that it is often useful to define a macro that takes
no arguments and whose definition begins with an identifier in parentheses. This rule
about spaces makes it possible for you to do either this:
(which defines `FOO' to take an argument and expand into minus the reciprocal of that
argument) or this:
(which defines `BAR' to take no argument and always expand into `(x) - 1 / (x)').
Note that the uses of a macro with arguments can have spaces before the left parenthesis;
it's the definition where it matters whether there is a space.
Stringification means turning a code fragment into a string constant whose contents are
the text for the code fragment. For example, stringifying `foo (z)' results in `"foo (z)"'.
#define WARN_IF(EXP) \
do { if (EXP) \
fprintf (stderr, "Warning: " #EXP "\n"); } \
while (0)
Here the actual argument for `EXP' is substituted once as given, into the `if' statement,
and once as stringified, into the argument to `fprintf'. The `do' and `while (0)' are a kludge
to make it possible to write `WARN_IF (arg);', which the resemblance of `WARN_IF' to
a function would make C programmers want to do; see section Swallowing the
Semicolon).
The stringification feature is limited to transforming one macro argument into one string
constant: there is no way to combine the argument with other text and then stringify it all
together. But the example above shows how an equivalent result can be obtained in ANSI
Standard C using the feature that adjacent string constants are concatenated as one string
constant. The preprocessor stringifies the actual value of `EXP' into a separate string
constant, resulting in text like
but the C compiler then sees three consecutive string constants and concatenates them
into one, producing effectively
do { if (x == 0) \
fprintf (stderr, "Warning: x == 0\n"); } \
while (0)
Concatenation
Concatenation means joining two strings into one. In the context of macro expansion,
concatenation refers to joining two lexical units into one longer one. Specifically, an
actual argument to the macro can be concatenated with another actual argument or with
fixed text to produce a longer name. The longer name might be the name of a function,
variable or type, or a C keyword; it might even be the name of another macro, in which
case it will be expanded.
struct command
{
char *name;
void (*function) ();
};
It would be cleaner not to have to give each command name twice, once in the string
constant and once in the function name. A macro which takes the name of a command as
an argument can make this unnecessary. The string constant can be created with
stringification, and the function name by concatenating the argument with `_command'.
Here is how it is done:
The usual case of concatenation is concatenating two names (or a name and a number)
into a longer name. But this isn't the only valid case. It is also possible to concatenate two
numbers (or a number and a name, such as `1.5' and `e3') into a number. Also, multi-
character operators such as `+=' can be formed by concatenation. In some cases it is even
possible to piece together a string constant. However, two pieces of text that don't
together form a valid lexical unit cannot be concatenated. For example, concatenation
with `x' on one side and `+' on the other is not meaningful because those two characters
can't fit together in any lexical unit of C. The ANSI standard says that such attempts at
concatenation are undefined, but in the GNU C preprocessor it is well defined: it puts the
`x' and `+' side by side with no particular special results.
Keep in mind that the C preprocessor converts comments to whitespace before macros
are even considered. Therefore, you cannot create a comment by concatenating `/' and `*':
the `/*' sequence that starts a comment is not a lexical unit, but rather the beginning of a
"long" space character. Also, you can freely use comments next to a `##' in a macro
definition, or in actual arguments that will be concatenated, because the comments will
be converted to spaces at first sight, and concatenation will later discard the spaces.
Predefined Macros
Several simple macros are predefined. You can use them without giving definitions for
them. They fall into two classes: standard macros and system-specific macros.
The standard predefined macros are available with the same meanings regardless of the
machine or operating system on which you are using GNU C. Their names all start and
end with double underscores. Those preceding __GNUC__ in this table are standardized
by ANSI C; the rest are GNU C extensions.
__FILE__
This macro expands to the name of the current input file, in the form of a C string
constant. The precise name returned is the one that was specified in `#include' or
as the input file name argument.
__LINE__
This macro expands to the current input line number, in the form of a decimal
integer constant. While we call it a predefined macro, it's a pretty strange macro,
since its "definition" changes with each new line of source code.
__INCLUDE_LEVEL__
This macro expands to a decimal integer constant that represents the depth of
nesting in include files. The value of this macro is incremented on every `#include'
command and decremented at every end of file.
__DATE__
This macro expands to a string constant that describes the date on which the
preprocessor is being run. The string constant contains eleven characters and looks
like `"Jan 29 1987"' or `"Apr 1 1905"'.
__TIME__
This macro expands to a string constant that describes the time at which the
preprocessor is being run. The string constant contains eight characters and looks
like `"23:59:01"'.
__STDC__
This macro expands to the constant 1, to signify that this is ANSI Standard C.
(Whether that is actually true depends on what C compiler will operate on the
output from the preprocessor.)
__GNUC__
This macro is defined if and only if this is GNU C. This macro is defined only
when the entire GNU C compiler is in use; if you invoke the preprocessor directly,
`__GNUC__' is undefined.
__GNUG__
The GNU C compiler defines this when the compilation language is C++; use
`__GNUG__' to distinguish between GNU C and GNU C++.
__cplusplus
The draft ANSI standard for C++ used to require predefining this variable. Though
it is no longer required, GNU C++ continues to define it, as do other popular C++
Appendix B (C#)
Several C# features aid in the construction of robust and durable applications: Garbage
collection automatically reclaims memory occupied by unused objects; exception
handling provides a structured and extensible approach to error detection and recovery;
and the type-safe design of the language makes it impossible to read from uninitialized
variables, to index arrays beyond their bounds, or to perform unchecked type casts.
C# has a unified type system. All C# types, including primitive types such as int and
double, inherit from a single root object type. Thus, all types share a set of common
operations, and values of any type can be stored, transported, and operated upon in a
consistent manner. Furthermore, C# supports both user-defined reference types and value
To ensure that C# programs and libraries can evolve over time in a compatible manner,
much emphasis has been placed on versioning in C#’s design. Many programming
languages pay little attention to this issue, and, as a result, programs written in those
languages break more often than necessary when newer versions of dependent libraries
are introduced. Aspects of C#’s design that were directly influenced by versioning
considerations include the separate virtual and override modifiers, the rules for method
overload resolution, and support for explicit interface member declarations.
The greatest power of C# is the availability of various collections. Collections like Data
Tables , HashTables, ArrayLists are used in this project and these collections helped us
to do coding in efficient way.
Array List:
The main problem of traditional arrays is that their size is fixed by the number you
specify when declaring the array variable: you cannot add items beyond the specified
dimension. Another limitation is that you cannot insert an item inside the list. To
overcome this, you can create a linked list. Instead of working from scratch, the .NET
Framework provides the ArrayList class. With the ArrayList class, you can add new
items to a list, insert items inside a list, arrange items of a list, check the existence of an
item in a list, remove an item from the list, inquire about the list, or destroy the list. These
operations are possible through various properties and methods.
HashTables:
Collections are used to store generic data types. Some of the collection classes available
in .NET Framework includes ArrayList, HashTable, Stack, and Queue. The Hashtable
object contains items in key/value pairs. The keys are used as indexes. We can search
value by using their corresponding key. Items are added to the Hashtable with the Add()
method. The data type of Hashtable is object and the default size of a Hashtable is 16.
Data Tables:
The DataTable has not received proper attentions in manybooks and articles. Often, the
authors get involved in explaining thedetails of a more versatile and novel object named
DataSet, thereby theDataTable object gets short-changed. The DataTable objects are
thefoundations of DataSets, and we will not be able to develop advanceddatabase
applications without understanding the principles of aDataTable.
Bibliography
Books
[B1] Beck Leland, An Introduction to System Programming, TMH 2006
[B2] Donovan, John, System programming, Pentice Hall Publications 2004
[B3] Dhamdhere D M, Systems programming and operating systems, TMH 2007
Websites
[W1] www.howstuffworks.com/analyser.html
[W2] www.codeguru.com/macro/mp2.html
[W3] www.programmersheaven.com/multimacro.htm