Macro Processor

68
Abstract 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)

description

Macro Processor for C++ created in C# 2008. MCA 4th Semester Project Complete Documentation.

Transcript of Macro Processor

Page 1: Macro Processor

Abstract

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)

Page 2: Macro Processor

(v)

gotoxy(10,3); //position cursor at x-axis 3 and y-axis 10

printf(“Code printed here”); //default printing function

/*This code can be replaced with the following code*/

#define DIS(y,x) gotoxy(x,y); printf //pre-processor directive

DIS(3,10) (“Code printed here”);

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.

Page 3: Macro Processor

Table of Contents

Topics

Page No.

Acknowledgements Abstract

iii 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) Appendix B (C# Programming) Bibliography

516265

Page 4: Macro Processor

Macro Processor for C/C++

Chapter – 1

INTRODUCTION

Department of Computer Science (MCA), Christ University 1

Page 5: Macro Processor

Macro Processor for C/C++

1.1. Problem Definition

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

Department of Computer Science (MCA), Christ University 2

Page 6: Macro Processor

Macro Processor for C/C++

significant loss of performance, especially if the functions carry small amounts of code in

them. Therefore, functions should not be used to hold replacement code, but to hold

relevant code that needs to be called only when required.

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

Compilation Issues: To increase readability of code, often, methods are written in

various files and included wherever necessary. Unfortunately, these individual files

cannot be compiled and then included during linking and execution. Therefore, this

approach cannot be used unless macros are used to include the text from these files in the

main source code file. This improves readability, reliability and debugging of the entire

project.

Department of Computer Science (MCA), Christ University 3

Page 7: Macro Processor

Macro Processor for C/C++

1.2. Block Diagram

The following is a block representation of the various actions that will take

place for a fully-processed file with macros expanded and removed.

Scan file for macros

Input file

Extract macros withname and definition

Macronames

Macrodefinitions

Scan for macro names

Replace macro namewith corresponding definition

Processedfile

Fig

1.a. Block representation of macro expansion

Department of Computer Science (MCA), Christ University 4

Page 8: Macro Processor

Macro Processor for C/C++

Chapter – 2

ANALYSIS

Department of Computer Science (MCA), Christ University 5

Page 9: Macro Processor

Macro Processor for C/C++

2.1. Domain Theory of the Problem The project involves the use of macros to help programmers write better

and more readable code. This task is a pre-processor task and does not result in

compilation of code, but is a step prior to compilation. The following are a set of domains

that macro processing touch upon. Some of these fields may not be largely involved with

macros, but contain generic concepts that largely affect systems programming. Systems

software are more concerned with tasks that help with the reduction of processing time

and overheads. Therefore macros help with the following

Less use of functions for calling repeated code

Less overhead when less functions are used

Reduced processing time. (Although, code may be repeated, it is required and is

not redundant. Therefore, the source code remains efficient)

Programming tool that is vastly used

Helps reduce spaghetti code and ultimately makes code more readable.

Helps with the use of variables even in repeated code. Similar to parameters for

functions, but without the overhead

Replaces text in code as the user wished and contains no references nor pointers

Usage of pre-processing tools that prepare source code for compilation

Conditional compilation depending on certain system architecture and

requirements

Providing dynamic and variable values to static chunks of text that require

replacement. (For example, the usage of #define with parameters that replaces

chunks of code with different values passed to it). This is performed without the

problem of programming overhead caused by the repeated use of functions.

Department of Computer Science (MCA), Christ University 6

Page 10: Macro Processor

Macro Processor for C/C++

2.2. SS Concept Used As already mentioned, there are many concepts associated with the concept

of systems software. Some of the concepts used in this project are as follows:

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

Therefore, the keyword “MACRO” is an indication of a start of a macro and the

following text is the name of the macro. This is required for storage and retrieval of

macros. The MEND is an indication of the macro. In more sophisticated languages such

as C#/C++, the MACRO keyword may be replaced by the “#” symbol and the <macro-

name> with the text that follows. The body of the macro is the text that follows the name

and the MEND is indicated by a newline character ‘\n’.

Here’s a typical example of how macros work in assembly language

mnemonics. This is a simple macro which takes no parameters

MACRO SUB

S 3,DATA

S 4,DATA

Department of Computer Science (MCA), Christ University 7

Page 11: Macro Processor

Macro Processor for C/C++

MEND

In the main program, the usage of the word SUB explicitly replaces that

text with the text that appears between the macro-name SUB and MEND. When the code

is submitted for compilation, it will not have the macro call within it and in fact will

resemble as though the user had placed the text there himself. This operation is

performed by the macro-processor. This task can therefore save considerable typing and

improve readability of code to a large extent. The same example can be applied to

existing high-level languages where a macro like LOOP j (1 to 5) can be used instead of

for (j=0; j<=5; j++)

Macros can do more than just replace text where it is required. Some of the

additional features of macros are as follows:

Macros can take parameters whose values can be replaced within the macro

expansion. This makes macro usage more dynamic

Macros can be used to conditionally include code depending on some condition.

This is useful for codes which may vary on different architectures.

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.

Department of Computer Science (MCA), Christ University 8

Page 12: Macro Processor

Macro Processor for C/C++

2.3. Hardware and Software Requirements The hardware and software requirements for this project are limited to only

the requirements of a C compiler on a UNIX or Windows machine.

Hardware Requirements

Pentium 60 MHz or higher

8 MB RAM or higher

10 MB hard-disk space free (not including swap space required for the OS)

Software Requirements

Borland Turbo C compiler or any other version compatible with IO streams

Windows 98 or later

Implementable on UNIX OS with minor adjustments

2.4. Description of Tools used

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.

C# is intended to be a simple, modern, general-purpose, object-oriented programming

language. Its development team is led by Anders Hejlsberg. The most recent version is

C# 3.0, which was released in conjunction with the .NET Framework 3.5 in 2007. The

next proposed version, 4.0, is in development.

Department of Computer Science (MCA), Christ University 9

Page 13: Macro Processor

Macro Processor for C/C++

Chapter – 3

SYSTEM DESIGN

Department of Computer Science (MCA), Christ University 10

Page 14: Macro Processor

Macro Processor for C/C++

3.1. Modular Detail

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

Page 15: Macro Processor

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:

Error-Checking: Whitespaces are once again a common programming error which

should not stall the compilation process. Therefore, once a macro name is encountered,

the scanning should begin once the whitespaces end. Other minor errors should be seen to

and reported and by-passed if possible.

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

Page 16: Macro Processor

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.

3.2. Details of Module

Project is implementing 2 pass Macro processor. Basic working of Passes

are as follows:

Pass I

• Examine every operation code

• Save all macro definitions in a MDT( Macro Definition Table)

• Save a copy of the input text, minus macro definitions on secondary storage for

use in pass II

• Prepare a Macro Name table(MNT)

Pass II

• Examine every string in program

• Replace each macro name with the appropriate text from the macro definition.

3.2 (a) Algorithm Pass 1

1. Search for # define construct

2. Enter Macro name and type in MNT

3. Enter Macro Definition in MDT

Department of Computer Science (MCA), Christ University 13

Page 17: Macro Processor

Macro Processor for C/C++

4. Enter Start and end index of MDT in MNT

3.2 (b) Algorithm Pass 2

1) Read string from source code till a break character is found : S1

2) Search S1 in MNT

If found then

Take type, argc from MNT : TT, argc

If tt=”O” || argc=0

Obtain start, ending index from MNT entry

For i=start to end

Extract MDT[i]

Extract Body column B1

Copy B1 to destination file

Set pointer to next line

End for

Copy break character to destination file

Else

Argtc=0

I=1

While ch = “)”

Read ch from file

While not ch= “,”

Str=str+ch

End while

Set argt[i]=str

Read next ch

End while

For i=start to end

Extract MDT[i]

Department of Computer Science (MCA), Christ University 14

Page 18: Macro Processor

Macro Processor for C/C++

Extract Body column B1 :str1

If there is no # in str1

Copy B1 to destination file

Set pointer to next line

Else

Finalstr=nul

I=0

While i<str.length

if str[i] = #

{

read in next string till u get non numeric

character; str2

get value from argt[str2] : val1

finalstr=finalstr+val1

i=str2.length+i+1;

}

Else

{

Finalstr=finalstr+str[i];

I++

}

Copy finalstr to destination file

Set pointer to next line

End for

Else

Copy to destination file + Break character.

Department of Computer Science (MCA), Christ University 15

Page 19: Macro Processor

Macro Processor for C/C++

Flowchart for PASS 1:

Department of Computer Science (MCA), Christ University 16

Page 20: Macro Processor

Macro Processor for C/C++

Flowchart for PASS 2:

3.3 Input Specification Valid C/C++ source code in file with .c or ,cpp extention.

3.4 Output Specification Code will be generated with expansion of Macros and without macro definitions. Various

data structures will be used for processing. These data structure will also be provided as

an output. The various data structures used and their format are as follows:

Pass I:

1. The Input macro source deck.

Department of Computer Science (MCA), Christ University 17

Page 21: Macro Processor

Macro Processor for C/C++

2. MDT, used to store the macro definitions.

3. MNT, used to store the names of the macro definitions.

4. ALA (Argument List Array), to substitute index markers for dummy args. Before

storing the macro def.

Pass 2:.

1. The output expanded source deck to be used as input to the assembler.

2. MDT and MNT created by Pass I.

3. ALA ( Argument List Array), to substitute macro call arguments for the index

markers in the stored macro definition.

MACRO NAME TABLE (MNT)

The macro name table is used to store the information related to macro.

Field name Description

mnt_index Index to macro name

Mnt_name Macro name

Mnt_type Type of macro-

o-object type macro

f-function type macro

Mdt_startindex Starting index of the macro body in macro definition table

Mdt_endindex End index of the macro body in macro definition table.

Department of Computer Science (MCA), Christ University 18

Page 22: Macro Processor

Macro Processor for C/C++

When a macro name is encountered it is added to MNT

Macro type is found i.e. either object type(o) or function type(f) and is added to

MNT .

The starting index(mdt_index) of macro body in MDT is added to MNT

The end index of macro body in MDT is also added to MNT

MACRO DEFINITION TABLE (MDT)

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.

It is a temporary table and is used during every preprocessing.

Field name Description

mdt_index Index of the macro definition

mdt_body Contains the body of macro definition which is

expanded when the call to macro is made.

Here the arguments are stored using positional

parameters; the arguments are given number according

to the way they appear in argument list.

Example-#1-denoted 1st argument

Department of Computer Science (MCA), Christ University 19

Page 23: Macro Processor

Macro Processor for C/C++

ARGUMENT LIST TABLE (ARGT)

There are two use of argument list table

During macro definition- when macros with arguments are obtained, each

argument is added to the ARGT using positional parameter notation.

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.

Field name Description

Arg_index Index of the argument

Arg_name Argument Name which can be either

arguments part of Macro Definition

arguments part of macro call

Department of Computer Science (MCA), Christ University 20

Page 24: Macro Processor

Macro Processor for C/C++

Chapter – 4

IMPLEMENTATION

Department of Computer Science (MCA), Christ University 21

Page 25: Macro Processor

Macro Processor for C/C++

4.1 Screen Shots

Department of Computer Science (MCA), Christ University 22

Page 26: Macro Processor

Macro Processor for C/C++

Department of Computer Science (MCA), Christ University 23

Page 27: Macro Processor

Macro Processor for C/C++

Department of Computer Science (MCA), Christ University 24

Page 28: Macro Processor

Macro Processor for C/C++

Department of Computer Science (MCA), Christ University 25

Page 29: Macro Processor

Macro Processor for C/C++

4.2 Sample Code richTextBox1.Text = "";

SourceCode.Items.Clear();

macrolist.Items.Clear();

Com_module.ff2.listBox1.Items.Clear();

int key;

string str, temp, str11;

char cc;

ArrayList colorcc = new ArrayList();

int cccount = 0;

int ii = 0, pp = 0, pt = 0, j, k, argtf = 0, acount = 0;

int mdtc = 0, mntc = 0, macroflag = 0;

DataTable mnt = new DataTable();

int mntind, start = 0, argtc = 0;

int mdtps = 0, mdtpe = 0;

int stringiflag = 0;

string name = null, type = null, tstr = null, fstr = null;

Hashtable argt = new Hashtable();

mnt.Columns.Add("Index", typeof(int));

mnt.Columns.Add("Name", typeof(string));

mnt.Columns.Add("Type", typeof(string));

mnt.Columns.Add("start", typeof(int));

mnt.Columns.Add("end", typeof(int));

mnt.Columns.Add("Argc", typeof(int));

string str1 = null, temp1;

DataTable mdt = new DataTable();

mdt.Columns.Add("Index", typeof(int));

mdt.Columns.Add("Body", typeof(string));

OpenFileDialog ftp = new OpenFileDialog();

Department of Computer Science (MCA), Christ University 26

Page 30: Macro Processor

Macro Processor for C/C++

ftp.Title = "C++ Files";

ftp.Filter = "All C++ File (*.cpp)|*.cpp";

if (ftp.ShowDialog() == DialogResult.Cancel)

return;

filetext.Text = ftp.FileName;

FileStream fs1 = new FileStream(filetext.Text, FileMode.Open, FileAccess.Read);

StreamReader sourcesr = new StreamReader(fs1);

while (sourcesr.Peek() != -1)

{

argtc = 0;

acount = 0;

argtf = 0;

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')

{

if (temp[7].ToString() == " ")

{

for (j = 8; temp[j].ToString() == " "; j++)

{

Department of Computer Science (MCA), Christ University 27

Page 31: Macro Processor

Macro Processor for C/C++

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;

Department of Computer Science (MCA), Christ University 28

Page 32: Macro Processor

Macro Processor for C/C++

//mdt.Rows.Add(mdtc, str1);

}

} 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

{

Department of Computer Science (MCA), Christ University 29

Page 33: Macro Processor

Macro Processor for C/C++

str += temp[j];

}

j++;

}

Com_module.ff2.listBox1.Items.Add("");

Com_module.ff2.listBox1.Items.Add("Macro -> " + name);

for (int a = 1; a <= argt.Count; a++)

{

Com_module.ff2.listBox1.Items.Add(a + " -> " + argt[a]);

}

}

else

{

j++;

}

do

{

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++)

{

Department of Computer Science (MCA), Christ University 30

Page 34: Macro Processor

Macro Processor for C/C++

if (IsAlpha(temp1[k].ToString()) == false &&

IsInteger(temp1[k].ToString()) == false)

{

if (argt.ContainsValue(str) == true)

{

for (int a = 1; a <= argt.Count; a++)

{

if (argt[a].ToString() == str)

{

str = "@" + a.ToString();

}

}

}

str1 = str1 + str + temp1[k];

str = null;

}

else

{

str += temp1[k];

}

}

Department of Computer Science (MCA), Christ University 31

Page 35: Macro Processor

Macro Processor for C/C++

}

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);

Department of Computer Science (MCA), Christ University 32

Page 36: Macro Processor

Macro Processor for C/C++

StreamReader sour = new StreamReader(fs2);

while (sour.Peek() != -1)

{

str = null;

stringiflag = 0;

str = sour.ReadLine();

if (str == "")

continue;

temp = str;

if (temp[0] == '#' && temp[1] == 'd' && temp[2] == 'e' && temp[3] == 'f' &&

temp[4] == 'i' && temp[5] == 'n' && temp[6] == 'e')

{

do

{

j = temp.Length;

j = j - 1;

if (temp[j] == '\\')

{

temp = sour.ReadLine();

continue;

}

} while (temp[temp.Length - 1] == '\\');

}

else

{

j = 0;

key = 0;

temp = str;

str1 = null;

str = null;

Department of Computer Science (MCA), Christ University 33

Page 37: Macro Processor

Macro Processor for C/C++

temp.Trim();

for (k = 0; k < temp.Length; k++)

{

key = 0;

if (temp[k] == '"')

{

str = str + temp[k].ToString();

do

{

k++;

str = str + temp[k].ToString();

} while (temp[k] != '"');

k++;

}

if (IsAlpha(temp[k].ToString()) == false && IsInteger(temp[k].ToString()) ==

false)

{

for (j = 0; j < mnt.Rows.Count; j++)

{

if (mnt.Rows[j][1].ToString() == str)

{

mdtps = int.Parse(mnt.Rows[j][3].ToString());

mdtpe = int.Parse(mnt.Rows[j][4].ToString());

key = 1;

name = str;

acount = int.Parse(mnt.Rows[j][5].ToString());

type = mnt.Rows[j][2].ToString();

}

}

if (key == 1)

{

Department of Computer Science (MCA), Christ University 34

Page 38: Macro Processor

Macro Processor for C/C++

if (type == "O")

{

str = null;

for (j = mdtps - 1; j <= mdtpe - 1; j++)

{

str = null;

if (j > mdtps - 1)

{

richTextBox1.Text = richTextBox1.Text + "\n";

}

str = str + mdt.Rows[j][1];

richTextBox1.Text = richTextBox1.Text + str;

colorcc.Add(richTextBox1.Text.Length - str.Length);

colorcc.Add(str.Length);

colorcc.Add(Color.HotPink);

cccount = cccount + 3;

//richTextBox1.Select(richTextBox1.SelectionStart, str.Length);

//MessageBox.Show(richTextBox1.SelectionStart.ToString() );

//MessageBox.Show(richTextBox1.SelectionLength.ToString());

richTextBox1.SelectionColor = Color.BlueViolet;

}

richTextBox1.Text = richTextBox1.Text + temp[k].ToString();

}

if (type == "F")

{

str = null;

Department of Computer Science (MCA), Christ University 35

Page 39: Macro Processor

Macro Processor for C/C++

str1 = null;

argt.Clear();

for (int i = 0; i < acount; i++)

{

argt.Add(i, "");

k++;

while (temp[k] != ',' && temp[k] != ')')

{

argt[i] = argt[i] + temp[k].ToString();

k = k + 1;

}

}

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";

}

str = str + mdt.Rows[j][1];

richTextBox1.Text = richTextBox1.Text + str;

Department of Computer Science (MCA), Christ University 36

Page 40: Macro Processor

Macro Processor for C/C++

colorcc.Add(richTextBox1.Text.Length - str.Length);

colorcc.Add(str.Length);

colorcc.Add(Color.Brown);

cccount = cccount + 3;

//richTextBox1.Select(richTextBox1.SelectionStart, str.Length);

//MessageBox.Show(richTextBox1.SelectionStart.ToString() );

//MessageBox.Show(richTextBox1.SelectionLength.ToString());

richTextBox1.SelectionColor = Color.BlueViolet;

}

richTextBox1.Text = richTextBox1.Text + temp[k].ToString();

}

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";

}

Department of Computer Science (MCA), Christ University 37

Page 41: Macro Processor

Macro Processor for C/C++

str = mdt.Rows[j][1].ToString();

if (str.IndexOf("##") >= 0)

{

string str111 = null;

int kkk = str.IndexOf("##");

for (int iii = 0; iii < kkk; iii++)

str111 = str111 + str[iii].ToString();

for (int iii = kkk + 2; iii < str.Length; iii++)

str111 = str111 + str[iii].ToString();

str = str111;

}

for (ii = 0; ii < str.Length; ii++)

{

fstr = null;

stringiflag = 0;

if (str[ii] == '#')

{

if (str[ii + 1] == '@')

{

ii++;

stringiflag = 1;

}

}

if (str[ii] == '@')

{

while (ii < str.Length - 1 && IsInteger(str[ii + 1].ToString())

== true)

{

Department of Computer Science (MCA), Christ University 38

Page 42: Macro Processor

Macro Processor for C/C++

fstr = fstr + str[ii + 1];

ii = ii + 1;

}

pp = int.Parse(fstr);

if (stringiflag == 0)

{

str1 = str1 + argt[pp - 1].ToString();

}

else

{

str11 = argt[pp - 1].ToString();

string strs = null;

for (int sst = 0; sst < str11.Length; sst++)

{

if (str11[sst].ToString() == "\"")

{

if (sst == 0)

{

strs = strs + "\\";

}

strs = strs + str11[sst];

}

else

{

if (sst + 1 < str11.Length && str11[sst + 1].ToString()

== "\"")

Department of Computer Science (MCA), Christ University 39

Page 43: Macro Processor

Macro Processor for C/C++

{

strs = strs + str11[sst];

strs = strs + "\\";

}

else

{

strs = strs + str11[sst];

}

}

}

strs = "\"" + strs + "\"";

str1 = str1 + strs;

//str1 = str1 + "\"" + argt[pp - 1].ToString() + "\"";

}

}

else

{

str1 = str1 + str[ii];

}

}

richTextBox1.Text = richTextBox1.Text + str1;

colorcc.Add(richTextBox1.Text.Length - str1.Length);

colorcc.Add(str1.Length);

colorcc.Add(Color.Green);

cccount = cccount + 3;

Department of Computer Science (MCA), Christ University 40

Page 44: Macro Processor

Macro Processor for C/C++

//richTextBox1.Select(richTextBox1.SelectionStart, str.Length);

//MessageBox.Show(richTextBox1.SelectionStart.ToString() );

//MessageBox.Show(richTextBox1.SelectionLength.ToString());

}

richTextBox1.Text = richTextBox1.Text + temp[k].ToString();

}

}

}

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";

}

Department of Computer Science (MCA), Christ University 41

Page 45: Macro Processor

Macro Processor for C/C++

}

for (j = 0; j < cccount; j = j + 3)

{

richTextBox1.SelectionStart = int.Parse(colorcc[j].ToString());

richTextBox1.SelectionLength = int.Parse(colorcc[j + 1].ToString());

richTextBox1.SelectionColor = (Color)colorcc[j + 2];

}

}

Department of Computer Science (MCA), Christ University 42

Page 46: Macro Processor

Macro Processor for C/C++

Chapter – 5

TESTING

Department of Computer Science (MCA), Christ University 43

Page 47: Macro Processor

Macro Processor for C/C++

5.1. Test Cases

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

Department of Computer Science (MCA), Christ University 44

Page 48: Macro Processor

Macro Processor for C/C++

program highlights all other directives that are not #define as possible errors and may

require rectification. The directives that do not match are enclosed in *** along with the

line number to bring it to the attention of the programmer. During, macro expansion,

directives that are not of the conditional compiling type are ignored and the line

completely skipped and not included in the final source code. This is because other

directives may have been valid directives that were successfully expanded or raised as

errors in the first pass. Either way, these lines should not be included in the final source

code. Care should be taken by the programmer to not include parts of the intended source

code in the same line as a pre-processor directive.

5.2. Test Reports

During the implementation of the program, there were many small

programs setup to ensure that the proper testing methods were used. Since the application

is divided into largely two modules, it is necessary to test the operation and results of

each module. For software testing, thorough verification of code and repeated executions

with various scenarios and data are tested. Logical verification by flow of data has to be

determined as early as possible, so that rectification of code can be done easily. The

corresponding output values for each module are confirmed and changes made in

correspondence with the output observed. For example, each module was individually

designed to suit the requirements of that module. The scanning module contained only

those details that were relevant to it. All operations for that module were tested and

checked individually. Modules with the least functional dependencies can be designed

first, so that they can be used by the more complex data dependencies which may have

references to it. From the very design of the project, the functionality was seen as several

modules that could exist by passing certain data amongst themselves when required. For

unit testing, the data that was required from other modules were either provided by the

other module directly, if already designed or were provided with dummy values (stubs)

that could act as potential values that could be passed to it. For this error-handling,

Department of Computer Science (MCA), Christ University 45

Page 49: Macro Processor

Macro Processor for C/C++

procedures were setup to ensure that it could collect only data that was required by it. The

very design of the program often ensured that only correct values may be passed when

required.

The application is complete only if the modules are working in tandem.

Hence, after the individual modules are tested, it is imperative to perform the integration

test. An interface between the modules is necessary. In this application, there is some

interface between modules. For example, the input file name is required for the second

pass scan, which it receives from the result of the first pass. It was important to note the

difference between data that arrived during an execution of a function.

Department of Computer Science (MCA), Christ University 46

Page 50: Macro Processor

Macro Processor for C/C++

Chapter – 6

CONCLUSION

Department of Computer Science (MCA), Christ University 47

Page 51: Macro Processor

Macro Processor for C/C++

6.1. Advantages and Disadvantages

The following are the major advantages of the project

Effectively replaces code that was meant for replacement with the help of macros.

Used concepts such as file pointers, structures to carry out its tasks

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.

Produces the output file, even if there are errors or warnings in the input file.

Maintains a separate input file and a separate output file for data verification and

rectification.

Maintains macro names and their definitions in structures, thereby reducing the

amount of resources involved with character arrays and is useful for debugging

purposes.

Tabs and whitespaces and original contents of the input file are maintained as they

are even in the final source code file.

The following are the major disadvantages of the project

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

Department of Computer Science (MCA), Christ University 48

Page 52: Macro Processor

Macro Processor for C/C++

6.2. Future Enhancements

Based on the development of the project, there is sufficient scope for

further enhancement. Enhancements can be made by way of improving on existing

features, addition of new features, removal of constraints and increasing flexibility to

macros. Some of the possible future enhancements are as follows:

Taking care of conditional macros

Conditional macros like the #if, #unif, #ifdef, #elif, #else are not taken into

account in

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.

Department of Computer Science (MCA), Christ University 49

Page 53: Macro Processor

Macro Processor for C/C++

REFERENCES

Department of Computer Science (MCA), Christ University 50

Page 54: Macro Processor

Macro Processor for C/C++

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

A simple macro is a kind of abbreviation. It is a name which stands for a fragment of

code. Some people refer to these as manifest constants.

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,

#define BUFFER_SIZE 1020

defines a macro named `BUFFER_SIZE' as an abbreviation for the text `1020'.

Therefore, if somewhere after this `#define' command there comes a C statement of the

form

Macros with Arguments

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

Department of Computer Science (MCA), Christ University 51

Page 55: Macro Processor

Macro Processor for C/C++

any valid C identifiers, separated by commas and optionally whitespace. The open-

parenthesis must follow the macro name immediately, with no space in between.

For example, here is a macro that computes the minimum of two numeric values, as it is

defined in many C programs:

#define min(X, Y) ((X) < (Y) ? (X) : (Y))

(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

((1) < (2) ? (1) : (2))

where `1' has been substituted for `X' and `2' for `Y'.

Likewise, `min (x + 28, *p)' expands into

((x + 28) < (*p) ? (x + 28) : (*p))

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,

macro (array[x = y, x + 1])

Department of Computer Science (MCA), Christ University 52

Page 56: Macro Processor

Macro Processor for C/C++

passes two arguments to macro: `array[x = y' and `x + 1]'. If you want to supply `array[x

= y, x + 1]' as an argument, you must write it as `array[(x = y, x + 1)]', which is

equivalent C code.

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:

((((a) < (b) ? (a) : (b))) < (c)

? (((a) < (b) ? (a) : (b)))

: (c))

(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:

#define foo0() ...

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).

Department of Computer Science (MCA), Christ University 53

Page 57: Macro Processor

Macro Processor for C/C++

Such dual use of one name could be confusing and should be avoided except when the

two meanings are effectively synonymous: that is, when the name is both a macro and a

function and the two have similar effects. You can think of the name simply as a

function; use of the name for purposes other than calling it (such as, to take the address)

will refer to the function, while calls will expand the macro and generate better but

equivalent code. For example, you can use a function named `min' in the same source file

that defines the macro. If you write `&min' with no argument list, you refer to the

function. If you write `min (x, bb)', with an argument list, the macro is expanded. If you

write `(min) (a, bb)', where the name `min' is not followed by an open-parenthesis, the

macro is not expanded, so you wind up with a call to the function `min'.

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:

#define FOO(x) - 1 / (x)

(which defines `FOO' to take an argument and expand into minus the reciprocal of that

argument) or this:

#define BAR (x) - 1 / (x)

(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.

Department of Computer Science (MCA), Christ University 54

Page 58: Macro Processor

Macro Processor for C/C++

Stringification

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)"'.

In the C preprocessor, stringification is an option available when macro arguments are

substituted into the macro definition. In the body of the definition, when an argument

name appears, the character `#' before the name specifies stringification of the

corresponding actual argument when it is substituted at that point in the definition. The

same argument may be substituted in other places in the definition without stringification

if the argument name appears in those places with no `#'.

Here is an example of a macro definition that uses stringification:

#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

Department of Computer Science (MCA), Christ University 55

Page 59: Macro Processor

Macro Processor for C/C++

do { if (x == 0) \

fprintf (stderr, "Warning: " "x == 0" "\n"); } \

while (0)

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)

Stringification in C involves more than putting doublequote characters around the

fragment; it is necessary to put backslashes in front of all doublequote characters, and all

backslashes in string and character constants, in order to get a valid C string constant with

the proper contents. Thus, stringifying `p = "foo\n";' results in `"p = \"foo\\n\";"'.

However, backslashes that are not inside of string or character constants are not

duplicated: `\n' by itself stringifies to `"\n"'.

Whitespace (including comments) in the text being stringified is handled according to

precise rules. All leading and trailing whitespace is ignored. Any sequence of whitespace

in the middle of the text is converted to a single space in the stringified result.

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.

Department of Computer Science (MCA), Christ University 56

Page 60: Macro Processor

Macro Processor for C/C++

When you define a macro, you request concatenation with the special operator `##' in the

macro body. When the macro is called, after actual arguments are substituted, all `##'

operators are deleted, and so is any whitespace next to them (including whitespace that

was part of an actual argument). The result is to concatenate the syntactic tokens on either

side of the `##'.

Consider a C program that interprets named commands. There probably needs to be a

table of commands, perhaps an array of structures declared as follows:

struct command

{

char *name;

void (*function) ();

};

struct command commands[] =

{

{ "quit", quit_command},

{ "help", help_command},

...

};

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:

#define COMMAND(NAME) { #NAME, NAME ## _command }

Department of Computer Science (MCA), Christ University 57

Page 61: Macro Processor

Macro Processor for C/C++

struct command commands[] =

{

COMMAND (quit),

COMMAND (help),

...

};

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.

Department of Computer Science (MCA), Christ University 58

Page 62: Macro Processor

Macro Processor for C/C++

Standard Predefined 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.

This and `__FILE__' are useful in generating an error message to report an

inconsistency detected by the program; the message can state the source line at

which the inconsistency was detected. For example,

fprintf (stderr, "Internal error: "

"negative string length "

"%d at %s, line %d.",

length, __FILE__, __LINE__);

A `#include' command changes the expansions of `__FILE__' and `__LINE__' to

correspond to the included file. At the end of that file, when processing resumes

on the input file that contained the `#include' command, the expansions of

`__FILE__' and `__LINE__' revert to the values they had before the `#include'

(but `__LINE__' is then incremented by one as processing moves to the line after

the `#include').

Department of Computer Science (MCA), Christ University 59

Page 63: Macro Processor

Macro Processor for C/C++

The expansions of both `__FILE__' and `__LINE__' are altered if a `#line'

command is used. See section Combining Source Files.

__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++

Department of Computer Science (MCA), Christ University 60

Page 64: Macro Processor

Macro Processor for C/C++

compilers. You can use `__cplusplus' to test whether a header is compiled by a C

compiler or a C++ compiler.

__STRICT_ANSI__

This macro is defined if and only if the `-ansi' switch was specified when GNU C

was invoked. Its definition is the null string. This macro exists primarily to direct

certain GNU header files not to define certain traditional Unix constructs which

are incompatible with ANSI C.

__BASE_FILE__

This macro expands to the name of the main input file, in the form of a C string

constant. This is the source file that was specified as an argument when the C

compiler was invoked.

__VERSION__

This macro expands to a string which describes the version number of GNU C.

The string is normally a sequence of decimal numbers separated by periods, such

as `"1.18"'. The only reasonable use of this macro is to incorporate it into a string

constant.

__OPTIMIZE__

This macro is defined in optimizing compilations. It causes certain GNU header

files to define alternative macro definitions for some system library functions. It is

unwise to refer to or test the definition of this macro unless you make very sure

that programs will execute with the same effect regardless.

__CHAR_UNSIGNED__

This macro is defined if and only if the data type char is unsigned on the target

machine. It exists to cause the standard header file `limit.h' to work correctly. It is

bad practice to refer to this macro yourself; instead, refer to the standard macros

defined in `limit.h'. The preprocessor uses this macro to determine whether or not

to sign-extend large character constants written in octal; see section The `#if'

Command.

Department of Computer Science (MCA), Christ University 61

Page 65: Macro Processor

Macro Processor for C/C++

Appendix B (C#)

C# (pronounced “See Sharp”) is a simple, modern, object-oriented, and type-safe

programming language. C# has its roots in the C family of languages and will be

immediately familiar to C, C++, and Java programmers. C# is standardized by ECMA

International as the ECMA-334 standard and by ISO/IEC as the ISO/IEC 23270

standard. Microsoft’s C# compiler for the .NET Framework is a conforming

implementation of both of these standards.

C# is an object-oriented language, but C# further includes support for component-

oriented programming. Contemporary software design increasingly relies on software

components in the form of self-contained and self-describing packages of functionality.

Key to such components is that they present a programming model with properties,

methods, and events; they have attributes that provide declarative information about the

component; and they incorporate their own documentation. C# provides language

constructs to directly support these concepts, making C# a very natural language in which

to create and use software components.

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

Department of Computer Science (MCA), Christ University 62

Page 66: Macro Processor

Macro Processor for C/C++

types, allowing dynamic allocation of objects as well as in-line storage of lightweight

structures.

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.

The various collections in C# are as follows:

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.

Department of Computer Science (MCA), Christ University 63

Page 67: Macro Processor

Macro Processor for C/C++

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.

A DataTable is an innovative addition to theDot Net Framework. Often a new developer

may confuse it with a databasetable. Typically, one or more DataTables are used in a

DataSet toconstruct a detached mini-database in the client's cache. However, aDataTable

may stand alone by its own right, and we may use it in manysituations that do not

necessarily warrant database connectivity orDataSets.

A DataTable is a relational database-liketable in the memory. It has a structural definition

(like databasetable definition), and constraints like Unique constraints. We may

alsodevelop database-like views. We may create hierarchical relationshipsamong many

DataTables dynamically in a DataSet.

Department of Computer Science (MCA), Christ University 64

Page 68: Macro Processor

Macro Processor for C/C++

Department of Computer Science (MCA), Christ University 65

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