Anda di halaman 1dari 169

System Software and Compiler Design

SYSTEM SOFTWARE AND COMPILER DESIGN LABORATORY


PART A
LEX AND YACC PROGRAMS
Execute the following programs using LEX : 1) a. Program to count the number of characters, words, spaces and lines in a given input file. b. Program to count the numbers of comment lines in a given C program. Also eliminate them and copy the resulting program into separate file. 2) a. Program to recognize a valid arithmetic expression and to recognize the identifiers and operators present. Print them separately. b. Program to recognize whether a given sentence is simple or compound. 3) Program to recognize and count the number of identifiers in a given input file. Execute the following programs using YACC : 4) a. Program to recognize a valid arithmetic expression that uses operators +, -, * and /. b. Program to recognize a valid variable, which starts with a letter, followed by any number of letters or digits. 5) a. Program to evaluate an arithmetic expression involving operators +, -, * and . b. Program to recognize strings aaab, abbb, ab and a using the grammar (anbn, n>= 0). 6) Program to recognize the grammar (an b, n>= 10).

PART B
UNIX PROGRAMMING
1. a) b) Non-recursive shell script that accepts any number of argument and prints them in the Reverse order, (For example, if the script is named rargs, then executing rargs A B C should produce C B A on the standard output). C program that creates a child process to read commands from the standard input and execute them (a minimal implementation of a shell like program). You can assume that no arguments will be passed to the commands to be executed. Shell script that accepts two file names as arguments, checks if the permissions for these files are identical and if the permissions are identical, outputs the common permissions, otherwise outputs each file name followed by its permissions. C program to create a file with 16 bytes of arbitrary data from the beginning and another 16 bytes of arbitrary data from an offset of 48. Display the file contents

2.

a)

b)

System Software and Compiler Design

3.

a) b)

4.

a)

b)

to demonstrate how the hole in file is handled. Shell function that takes a valid directory names as an argument and recursively descends all the subdirectories, finds the maximum length of any file in that hierarchy and writes this maximum value to the standard output C program that accepts valid file names as command line arguments and for each of the arguments, prints the type of the file (Regular file, Directory file, Character special file, Block special file, Symbolic link etc.) Shell script that accepts file names specified as arguments and creates a shell script that contains this file as well as the code to recreate these files. Thus if the script generated by your script is executed, it would recreate the original files(This is same as the bundle script described by Brain W. Kernighan and Rob Pike in The Unix Programming Environment, Prentice Hall India). C program to do the following: Using fork( ) create a child process. The child process prints its own process-id and id of its parent and then exits. The parent process waits for its child to finish (by executing the wait( )) and prints its own process-id and the id of its child process and then exits.

COMPILER DESIGN
5. Write a C program to implement the syntax-directed definition of if E then S1 and if E then S1 else S2. (Refer Fig. 8.23 in the text book prescribed for 06CS62 Compiler Design, Alfred V Aho, Ravi Sethi, Jeffrey D Ullman: Compilers- Principles, Techniques and Tools, Addison-Wesley, 2007.) Write a yacc program that accepts a regular expression as input and produce its parse tree as output.

6.

Introduction to lex
The word lexical in the traditional sense means pertaining to words. In terms of programming languages, words are objects like variable names, numbers, keywords etc. Such words are traditionally called tokens. A lexical analyzer, or lexer for short, will take input as a string of individual letters and divide this string into tokens. Additionally, it will filter out whatever separates the tokens (the so-called white-space), i.e., lay-out characters (spaces,newlines etc.) and comments. The lexical analyzer is the first phase of a compiler. Its main task is to read the input characters and produce as output a sequence of tokens that the parser uses for syntax analysis.This interaction, summarized schematically in Fig. 1.1, is commonly implemented by making the lexical analyzer be a subroutine or a co routine of the parser. Several tools have been built for constructing lexical analyzers from special purpose notations based on regular expressions.In this section, we describe a particular tool, called Lex that has been widely used to specify lexical analyzers for a variety of languages. We refer to the tool as Lex compiler, and its input specification as the Lex language.

System Software and Compiler Design

token LEXICAL ANALYZER get next token PARSER

SYMBOL TABLE Fig. 1.1 : Interaction of lexical analyzer with parser


Lex is generally used in the manner depicted in Fig 1.2. First, a specification of a lexical analyzer is prepared by creating a program lex.l in the lex language. Then, lex.l is run through the Lex compiler to produce a C program lex.yy.c. The program lex.yy.c consists of a tabular representation of a transition diagram constructed from the regular expression of lex.l, together with a standard routine that uses the table to recognize lexemes. The actions associated with regular expression in lex.l are pieces of C code and are carried over directly to lex.yy.c. Finally lex.yy.c is run through the C compiler to produce an object program a.out, which is the lexical analyzer that transforms an input stream into a sequence of tokens.

Lex source Program lex.1

Lex compiler

lex.yy.c

lex.yy.c

C Compiler

a.out

input stream

a.out

Sequence of tokens

Fig. 1.2 : Creating a lexical analyzer with Lex

System Software and Compiler Design

Lex specifications
A Lex program consists of three parts : declarations %% translation rules %% auxiliary procedures The declarations section includes declarations of variables,constants,and regular definitions. The translation rules of a lex program are statements of the form R1 {action1} R2 {action2} .... .... Rn {action n} where each Ri is regular expression and each action i, is a program fragment describing what action the lexical analyzer should take when pattern Ri matches lexeme.Typically, action i will return control to the parser. In Lex actions are written in C;in general,however,they can be in any implementation language. The third section holds whatever auxiliary procedures are needed by the actions.

The parser obtains a string of tokens from the lexical analyzer and verifies that the string can be generated by grammar for the source language. We expect the parser to report any syntax errors in an intelligible fashion. It should also recover from commonly occurring errors so that it can continue processing the remainder of its input. We know that programs can contain errors at many different levels. For example, errors can be 1. Lexical ,such as misspelling an identifier,keyword,or operator. 2. Syntactic,such as arithmetic expression with unbalanced parentheses 3. Sematic,such as an operator applied to an incompatible operand. 4. Logical,such as infinitely recursive call. Often much of the error detection and recovery in a compiler is centered around the syntax analysis phase

THE ROLE OF PARSER

LEXICAL CONVENTIONS
The notations for specifying tokens : 1. . Matches any single character except the newline (\n) 2. 3. 4. * Matches zero or more copies of the preceding expression. [ ] A character class which matches any character within the brackets. ^ Matches the beginning of a line as the first character of a regular expression.

System Software and Compiler Design

5. 6. 7. 8. 9.

$ Matches the end of line as the last character of a regular expression. \ Used to escape metacharacter. + Matches one or more occurrence of the preceding regular expression. For example [0-9]+ matches .12.,.9..but not an empty string. ? Matches zero or one occurrence | Matches either the preceding regular expression or the following expression. For example are | is | because matches any three words.

10. / Matches the preceding regular expression but only if followed by the regular expression. 11. ( ) Groups of series of regular expressions together into a new regular expression. 12. Blanks between tokens are optional, with the exception that keywords must be surrounded by blanks, new lines, the beginning of the program, or the final dot.

Execute the following programs using LEX :


1a. Program to count the number of characters, words, spaces and lines in a given input file. Program name: 1a.l %{ int characters=0,spaces=0,words=0,lines=0; %} %% [\n] {lines++;} [^\t\n ]+ {characters+=yyleng,words++;} " " {spaces++;} %% int main(int argc,char *argv[]) { yyin=fopen(argv[1],"r"); yylex(); printf("Number of characters:%d\n",characters); printf("Number of spaces:%d\n",spaces); printf("Number of words:%d\n",words); printf("Number of lines:%d\n",lines); } Output: $ vi sample.txt This is the input to the first lab program on lex

System Software and Compiler Design

$ lex 1a.l $ cc o 1a lex.yy.c -ll $./1a sample.txt Number Number Number Number of of of of characters: 39 spaces: 9 words: 11 lines: 2

Explanation The first section, the definition section, introduces any initial C program code we want copied into final program. i.e. Take a variable for representing a character, line, space and words. %{ int characters=0,lines=0,spaces=0,words=0; %} The next section is the rules section .Each rule is made of two parts: a pattern and an action, separated by white space. The lexer that lex generates will execute the action when it recognizes the pattern. 1. To count the number of line the pattern: [\n] .After lexer recognizes the [\n] pattern it should perform the action .Here the action is to increment the line value, so the action is represented by {lines++;} To count the space the pattern : . ..After lexer recognizing the . . pattern it should perform the action. Here the action is to increment the space value, so the action is represented by {spaces++;} To count the words and characters the regular expression : [^\t\n]+. Here ^ matches the beginning of a line as the first character of a regular expression. The tool lex provides an internal variable yyleng which contains the length of the string our lexer recognized. + symbol matches one or more occurrence of the preceding regular expression. So the action is represented by {characters+=yyleng,words++;}

2.

3.

The next section is procedures section, we know that when a program is invoked, the execution starts from the function main( ). We can pass the parameters to the function main( ) whenever the program is invoked and are called command line parameters. To access the command line parameters the function main should have the following format : Syntax : main(int argc, char *argv[]) { -----------}

System Software and Compiler Design

The function main( ) can take two arguments namely argc and argv where argc must be an integer variable whereas argv is an array of strings.argc indicates the number of parameters passed and argv represents a parameter that is passed to function main. The file should be opened before reading or writing with the help of fopen function Syntax : fopen(char *filename, char *mode) Return values -file pointer if successful. -NULL if unsuccessful.

A lex lexer reads its input from the standard I/O file yyin.The default value of yyin is stdin, since the default input source is standard input. If you to change the source you should mentioned it explicitly. yylex( ) : You call yylex ( ) to start or resume scanning. If a lex action does a return to pass a value to the calling program ,the next call to yylex( ) will continue from the point where it left off. All the code in the rules section is copied into yylex( ). 1b. Program to count the numbers of comment lines in a given C program. Also eliminate them and copy the resulting program into separate file. Program name : 1b.l %{ int comment=0; %} %% "/*"[\n]*.*[\n]*"*/" {comment++;} "/*"[\"*/"]* { fprintf(yyout," "); } %% int main() { yyin=fopen(argv[1],"r"); yyout=fopen(argv[2],"w"); yylex(); printf("Number of comment lines in the given file: %d\n",comment); } Output : $ vi input /* this is a sample input */ void main() { int a,b,c; /* variable declaration */

System Software and Compiler Design

printf(\n hello); /* code of the program */ } $ lex 1b.l $ cc o 1b lex.yy.c -ll $ ./1b input output Number of comment lines in the given file: 3 $ cat output void main() { int a,b,c; printf(\n hello); } Explanation The first section, the definition section, introduces any initial C program code we want copied into final program. i.e. Take a variable for representing comment line. %{ int comment=0; %} The next section is the rules section .Each rule is made of two parts: a pattern and an action, separated by white space. The lexer that lex generates will execute the action when it recognizes the pattern. 1. C style comment line is enclosed with /* and */ characters. To count the numbers of comment line the pattern: "/*"[\n]*.*[\n]*"*/". After lexer recognizes the "/*"[\n]*.*[\n]*"*/" pattern it should perform the action. Here the action is to increment the comment value , so the action is represented by {comment++;}. As you know . (dot) doesn.t match the newline character ,it matches the character. 2. Now to eliminate the comment line and then to copy the remaining content in file the pattern : /*"[\"*/"]* . Here the metacharacter \ is to suppress the character *. After lexer recognizes the pattern it inserts whitespace in the place of comment line and copies the remaining content of the file.

fprintf()function The function is similar to that of printf( ) except the syntax .The Prototype of fprintf is : Syntax : fprintf(fp, "control string" , list) fp : file fpointer associated with the file.

System Software and Compiler Design

2a. Program to recognize a valid arithmetic expression and to recognize the identifiers and operators present. Print them separately. Program name : 2a.l %{ int operatorcnt=0,identifiercnt=0,bracket=0; %} %% [+] {printf("+");operatorcnt++;} [-] {printf("-");operatorcnt++;} [*] {printf("*");operatorcnt++;} [/] {printf("/");operatorcnt++;} [a-zA-Z0-9]+ { identifiercnt++;} [(] {bracket++;} [)] {bracket--;} %% int main() { printf("Enter the expression:\n"); yylex(); printf("Number of Operators=%d\n", operatorcnt); printf("Number of Identifiers=%d\n",identifiercnt); if(operatorcnt >= identifiercnt || bracket!=0 || identifiercnt ==1) printf("Invalid expression\n"); else printf("Valid expression\n"); } $ lex 2a.l $ cc o 2a lex.yy.c ll $ ./2a Enter the expression : a+b*c +* Number of Operators = 2 Number of Identifiers = 3 ( Press Control-d) Valid expression $ ./2a Enter the exprexssion : (1+2*3 +* Number of Operators = 2

10

System Software and Compiler Design

Number of Identifiers = 3 {Press Control-d Invalid expression $ ./2a Enter the exprexssion : (1+2*3) +* Number of Operators = 2 Number of Identifiers = 3 {Press Control-d Valid expression Explanation The first section, the definition section, introduces any initial C program code we want copied into final program. i.e. Take variables for representing the operators, identifiers and for brackets. %{ int operatorcnt=0,identifiercnt=0,bracket=0; %} The next section is the rules section .Each rule is made of two parts: a pattern and an action, separated by white space. The lexer that lex generates will execute the action when it recognizes the pattern. 1. To recognize the operators the pattern is : [ + ] ,[ - ],[ * ],[ / ]. After lexer recognizes the pattern it should perform the action .Here the action is to display the operator and to count the operator, so the action is represented by {printf("operator");operatorcnt++;} To recognize the identifiers the pattern is :[a-zA-Z0-9]+ . After lexer recognizes the pattern it should perform the action .Here the action is to increments the identifier value. To recognize the brackets the pattern is [ ( ] and [ )].After lexer recognizes the pattern it should perform the action. Here the action is to increment brackets and decrement the bracket values respectively.

2.

3.

2b. Program to recognize whether a given sentence is simple or compound. Program name : 2b.l %{ int flag=0; %}

System Software and Compiler Design

11

%% " and " | " or " | " but " | " because " | " than " {flag=1;} %% int main() { printf("Enter the sentence:\n"); yylex(); if(flag==1) printf("Given sentence is compound sentence\n"); else printf("Given sentence is simple sentence\n"); } Output : $ lex 2b.l $ cc o 2b lex.yy.c ll $ ./2b Enter the sentence This is ss lab This is ss lab (Press control-d) Given sentence is simple sentence $ ./2b Enter the sentence I and you Iyou (Press control-d) Given sentence is compund sentence Explanation The first section, the definition section, introduces any initial C program code we want copied into final program. i.e. Take variables for representing the words which leads to a compound statement. %{ int flag=0; %} The next section is the rules section .Each rule is made of two parts: a pattern and an action, separated by white space. The lexer that lex generates will execute the action when it recognizes the pattern.

12
1.

System Software and Compiler Design

List few words which lead to compound statement. After lexer recognizes the pattern it should perform the action .Here the action is to set the value as it recognizes the words in the given statement Program to recognize and count the number of identifiers in a given input file.

3.

%{ int count=0; %} %% ("int ")|("float ")|("double ")|("char ") { int ch; ch=input(); for(;;) { if(ch==',') { count++; } else if(ch==';') { count++; break; } ch = input(); } } %% int main(int argc, char *argv[]) { yyin=fopen(argv[1],"r"); yylex(); printf("Number of identifiers are :%d\n",count); } Output : $ vi input.txt int main() { int a,b,c; char x,y; printf(hello); } $ lex 3.l $ cc o 3 lex.yy.c ll $ ./3 input.txt Number of identifiers are 5

System Software and Compiler Design

13

YACC Introduction
The unix utility yacc (Yet Another Compiler Compiler) parses a stream of token, typically generated by lex, according to a user-specified grammar.

2.1 Structure of a yacc file


A yacc file looks much like a lex file : definitions %% rules %% Code Definition : All code between %{ and %} is copied to the beginning of the resulting C file. Rules : A number of combinations of pattern and action: if the action is more than a single command it needs to be in braces. Code : This can be very elaborate, but the main ingredient is the call to yylex, the lexical analyzer. If the code segment is left out, a default main is used which only calls yylex. Definition section There are three things that can go in the definitions section : C code : Any code between %{ and %} is copied to the C file. This is typically used for defining file variables, and for prototypes of routines that are defined in the code segment. Definitions : The definition section of a lex file was concerned with characters; in yacc this is tokens. Example : %token NUMBER. These token definitions are written to a .h file when yacc compiles this file.Associativity rules These handles associativity and priority of operators.

2.2 Lex Yacc interaction


Conceptually, lex parses a file of characters and outputs a stream of tokens; yacc accepts a stream of tokens and parses it, performing actions as appropriate. In practice, they are more tightly coupled. If your lex program is supplying a tokenizer, the yacc program will repeatedly call the yylex routine. The lex rules will probably function by calling return everytime they have parsed a token.If lex is to return tokens that yacc will process, they have to agree on what tokens there are.This is done as follows : For Example 1. The yacc file will have token definition %token NUMBER in the definitions section. 2. When the yacc file is translated with yacc .d , a header file y.tab.h is created that has definitions like #define NUMBER 258. 3. The lex file can then call return NUMBER, and the yacc program can match on this token.

14

System Software and Compiler Design

The rules section contains the grammar of the language you want to parse. This looks like statement : INTEGER = expression | expression ; expression : NUMBER + NUMBER | NUMBER - NUMBER ; This is the general form of context-free grammars, with a set of actions associated with each matching right-hand side. It is a good convention to keep non-terminals (names that can be expanded further) in lower case and terminals (the symbols that are finally matched) in upper case. The terminal symbols get matched with return codes from the lex tokenizer. They are typically defines coming from %token definitions in the yacc program or character values. Compiling and running a simple parser On a UNIX system, yacc takes your grammar and creates y.tab.c, the C Language parser, and y.tab.h, the include file with the token number definitions. Lex creates lex.yy.c,the C language lexer .You need only compile them together with the yacc and lex libraries. The Libraries contain usable default versions of all of the supporting routines, including main( ) that calls the parser yyparse( ) and exits. $ $ $ $ lex filename.l yacc -d filename.y cc lex.yy.c y.tab.c ll ./a.out /* makes lex.yy.c */ /* makes y.tab.c and y.tab.h */ /* compile and link C files */

2.3 Rules section

Execute the following programs using YACC : 4a. Program to recognize a valid arithmetic expression that uses operators +, -, * and /. Lex file-name : 4a.l %{ #include "y.tab.h" %} %% [a-zA-Z][a-zA-Z0-9]* {return ID;} [0-9]+ {return NUMBER;} . {return yytext[0];} \n {return 0;} %%

System Software and Compiler Design

15

Yacc file-name : 4a.y %token NUMBER ID %left '+''-' %left '*''/' %% expr:expr '+' expr; |expr '-' expr; |expr '*' expr; |expr '/' expr; |'('expr')' |NUMBER |ID ; %% int main() { printf("Enter the Expression\n"); yyparse(); printf("Valid Expression\n"); } int yyerror() { printf("Expression is invalid\n"); exit(0); } Output : $ lex 4a.l $ yacc d 4a.y $ cc o 4a lex.yy.c y.tab.c ll $ ./4a Enter the Expression a+b*c Valid Expression $./4a Enter the Expression a+b*c Expression is invalid Explanation LEXER(lex code) We need a lexer to feed it tokens. The yyparse( ) parser is the high level routine, and calls the lexer whenever it needs a token from the input .As soon as the lexer finds token of interest to the parser ,it return to the parser ,returning the token code as value. Yacc

16

System Software and Compiler Design

defines the token names in the parser as C preprocessor names in y.tab.h so the lexer can use them. 1. Strings of digits are number ,To match the string of digit the pattern is : [0-9]+. Action is to return the token NUMBER value. 2. Strings of alphabets are identifiers. To match an identifiers the pattern [a-zA-z][a-zA-Z0-9]*. Action is to return the token ID value.

3. . (dot) matches a character. Whenever a lexer matches a token , the text of the token is stored in the null terminated string yytext . This rule says to return any character otherwise not handled as a single character token to the parser. Character token are usually punctuation such as parentheses ,semicolons and single-character operator. If the parser receives a token that it doesn.t know about ,it generates a syntax error, so this rule lets you handle all of the single-character tokens easily while letting yacc.s error checking catch and complain about invalid input. 4. A newline (\n) character returns an end of input token(number zero ) to tell the parser that there is no more to read.

PARSER(Yacc code) The token definition for the number ad identifiers %token NUMBER ID Yacc lets you to specify the operator precedence.s explicitly. %left +- %left */ Each of these declarations defines a level of precedence. That .+.and .-. are left associative and have lower precedence level,.*. and ./. are left associative and have the higher precedence level. Grammar for an valid Expression is as follows expr:expr '+' expr; |expr '-' expr; |expr '*' expr; |expr '/' expr; |'('expr')' |NUMBER |ID yyparse( ) : The entry point to a yacc-generated parser is yyparse ( ).Whenever your programs call yyparse( ) ,the parser attempts to parse an input stream. The parser returns a value of zero if the parse succeeds and non-zero if not. yyerror( ) : Whenever a yacc parser detects a syntax error ,it calls yyerror ( ) to report the error to the user. 4b. Program to recognize a valid variable, which starts with a letter, followed by any number of letters or digits. Lex file-name : 4b.l

System Software and Compiler Design

17

%{ #include"y.tab.h" %} %% [0-9] {return DIG;} [a-z] {return LET;} . {return yytext[0];} \n {return 0;} /*Logical EOF*/ %% Yacc file-name : 4b.y %token LET %token DIG %% stmt:id {printf("Valid identifier \n");} ; id: letter next | letter {;} ; next: letter next | digit next | letter | digit {;} ; letter: LET {;} ; digit: DIG {;} ; %% int main() { printf("Enter an identifier:"); yyparse(); } int yyerror() { printf("Not a valid identifier\n"); exit(0); } Output : $ lex 4b.l $ yacc d 4b.y $ cc o 4b lex.yy.c y.tab.c ll

18

System Software and Compiler Design

$./4b Enter Valid $./4b Enter Not a

an identifier :abc21 indetitifier an identifier :21abc valid identifier

Explanation LEXER(lex code) 1. To match the digit the pattern is [0-9].Action is to return the token DIG value. 2. To match the letter the pattern is [a-z].Action is to return the token DIG value. PARSER(yacc code) The grammar to recognize a valid identifier statement: id ; id: letter next | letter {;} ; next: letter next | digit next | letter | digit {;} ; letter: LET {;} ; digit: DIG {;} 5a. Program to evaluate an arithmetic expression involving operators +, -, * and . Lex File-name : 5a.l %{ #include"y.tab.h" extern int yylval; %} %% [0-9]+ {yylval=atoi(yytext); return(NUM);} [ \t]; . {return yytext[0];} \n {return 0;} %% Yacc file-name : 5a.y %token NUM

System Software and Compiler Design

19

%left '+''-' %left '*''/' %% stmt : expr { printf("Result:%d\n",$1);return 0; } ; expr :expr'+'expr {$$=$1+$3;} | expr'-'expr {$$=$1-$3;} | expr'*'expr {$$=$1*$3;} | expr'/'expr {$$=$1/$3;} | '('expr')' {$$=-$2;} | NUM {$$=$1;} ; %% int main() { printf("Enter the expression\n"); yyparse(); } int yyerror() { printf("Invalid input\n"); exit(0); } Output : $ lex 5a.l $ yacc d 5a.y $ cc o 5a lex.yy.c y.tab.c -ll $ ./5a Enter the expression 5+3 Result:8 $./5a Enter the expression 4*5+2 Result:22 Explanation Lexer String of digit is number ,whitespace is ignored. Whenever the lexer returns a token to the parser ,if the toke has an associated value, the lexer must store the value in yylval befor returning. We explicitly declare yylval. Parser The grammar is as follows expr :expr'+'expr {$$=$1+$3;}

20
| | | | | ;

System Software and Compiler Design

expr'-'expr {$$=$1-$3;} expr'*'expr {$$=$1*$3;} expr'/'expr {$$=$1/$3;} '('expr')' {$$=-$2;} NUM {$$=$1;}

5b. Program to recognize strings .aaab., .abbb., .ab. and .a. using the grammar (an bn , n>= 0). Lex file-name : 5b.l %{ #include"y.tab.h" %} %% a {return A;} b {return B;} . {return yytext[0];} \n {return yytext[0];} %% Yacc file-name : 5b.y %token A B %% str : s'\n' {return 0;} s : A s B ; | ; %% int main() { printf("Enter the string\n"); yyparse(); printf("Valid string"); } int yyerror() { printf("Invalid string"); exit(0); } Output : $ lex 5b.l $ yacc d 5b.y

System Software and Compiler Design

21

$ cc o 5b lex.yy.c y.tab.c ll $ ./5b Enter the string aaaabbbb valid string $ ./5b Enter the string aabbbb Invalid string Explanation LEXER To match the string .a. the pattern is .a.. Action is to return the token A value . To match the string .b. the pattern is .b.. Action is to return the token B value . PARSER The grammar is as follow: string : s'\n' s:AsB; 6. Program to recognize the grammar (an b, n>=10). Lex file-name : 6.l %{ #include"y.tab.h" %} %% a {return A;} b {return B;} . {return yytext[0];} \n {return yytext[0];} %% Yacc file-name : 6.y %token A B %% str: s'\n' {return 0;} s : A A A A A A A A A A x B ; x : A x | ; %% int main() { printf("Enter the string\n"); yyparse();

22

System Software and Compiler Design

printf("Valid string"); } int yyerror() { printf("Invalid string"); exit(0); } Output : $ lex 6.l $ yacc d 6.y $ cc o 6 lex.yy.c y.tab.c ll $./6 Enter the string aaaaaaaaaaaab Valid string $./6 Enter the string aab Invalid string Explanation LEXER 1.To match the string .a. the pattern is .a.. Action is to return the token A value . 2.To match the string .b. the pattern is .b.. Action is to return the token B value . PARSER The grammar is as follow: string : s \n s:AAAAAAAAAAxB; x: Ax |;

INTRODUCTION TO SHELL PROGRAMMING


A set of commands that are taken together as a single unit within a file and executed at a stretch is called a shell program or a shell script. A shell script is named just like all other files. However, by convention shell script name uses .sh extension. A shell program runs in the interpretive mode, that is, one statement is executed at a time. Example :

#!/bin/sh echo Todays date is :date echo My shell : $SHELL

#to display the date

example.sh

System Software and Compiler Design

23

The first line is interpreter line. Here, this line specifies the shell we are using i.e Bourne shell A shell script is executed by using the shell command sh as shown below. $sh example.sh Today.s date is : Sat Jan 27 09:10:18 IST 2004 My Shell :/bin/sh Comments In shell scripts comments are written using the hash (#) character as the first character of the comment line. The read Command The read command or statement is the shell.s internal tool for taking the input from the user ,i.e., making scripts interactive. It is used with one or more variables. Input supplied through the standard input is read into the variables.

#!/bin/sh echo Enter the value of x read x echo The value of x is : $x value.sh
When you use a statement like read x the script pauses at that point to take input from the keyboard. Whatever you enter is stored in the variable x. Since this is a form of assignment ,no $ is used before x. To display that value we have to use $ symbol along with variable. Special parameters Used by Shell.

Variable $# $* $0 $1, $2, $3, ..... $? $$ $!

Significance Number of arguments specified in command line. Complete set of positional parameters as a single string. Name of the file or executed command. Positional parameters representing command line arguments. Exit status of last executed command. PID of current shell. PID of the last background job.

24

System Software and Compiler Design

Using command line

#!/bin/sh echo The program name : $0 echo The number of arguments specified is : $# echo The arguments are : $* echo Value of $1 and $2 command.sh
$ sh command.sh cse ise The program Name:command.sh The number of arguments specified is :2 The arguments are : cse ise Value of cse and ise The first argument is read by the shell into the parameter $1 ,the second argument into $2.We can use more positional parameters in this way up to $9.(and using the shift command, you can go beyond. The if Conditional This is the simplest of all the branching control structures. It has the following general formats.

i t

f s

Every if is close with corresponding fi ,and you.ll encounter an error of one is not present. If command succeeds ,the sequence of commands following it is executed .If command fails,then the else statement(if present) is executed. Using test and [ ] to evaluate expressions. When you use if to evaluate expressions, you need the test statement because the true or false values returned by expressions can.t be directly handled by if. test Uses certain operators to evaluate the condition and either a true or false exit status,which is then used by if for making decisions.

System Software and Compiler Design

25

Numerical comparison operators used by test

Operator -eq -ne -gt -ge -lt -le

Meaning Equal to Not equal to Greater than Greater than or equal to Less than Less than or equal to

The operators begins with . (hyphen) ,followed by a two-letter string. The operators are quite mnemonic; -eq implies equal to ,-lt less than and so on. Example : $ a=8 ; b=9 ; $ $a .eq $b ; echo $? $1 $ test $a .lt $b $0 expr : Computation expr can perform basic arithmetic operations (+,-,*,/,%). $ a=2 ; b=9 $ c= expr $x + $y ; echo .$c. $ 11 The operands must be enclosed on either side by whitespace. For multiplication we have to use \ (Escaping technique) to prevent the shell from interpreting it as metacharacter. while Looping while statement repeatedly performs a set of instructions until the control command returns a true exit status. The general syntax of this : while condition is true do commands done The commands enclosed by do and done are executed repeatedly as long as condition remains true. The case conditional In case statement ,the statement which matches an expression is executed. The general syntax of the case statement is as follows :

26

System Software and Compiler Design

case expression in pattern1)command1;; pattern2)command2;; pattern3)command2;; .... esac case first matches expression with pattern1.If match succeeds, the it.s executes command1.If matches fails, the pattern2 is matched ,and so forth. Each command list is terminated with a pair of semicolons, and the entire construct is closed with esac (reverse of case). eval command The use of eval command makes the shell to scan the command line once more, that is, second time and then actually executes the command line. Example : $ b=a $ c=b $ eval echo \$$c $ a The first two statements in this example are assignment statement. When the shell comes cross the third statement, because of eval; it first scans the statements once for any possible pre-evaluation or substitution. Here because of metacharacter \ the first $ is overlooked and the next variable $c gets evaluated resulting b. After this evaluation the third statement will be equivalent to echo $b. Then this statement gets executed as usual by the shell resulting as the answer.

PART B
UNIX PROGRAMMING
1. a) Non-recursive shell script that accepts any number of arguments and prints them in the reverse order.

Filename : 1a.sh echo "number len=$# while [ $len do eval echo len=`expr done of arguments are : $#" -ne 0 ] \$$len $len - 1`

System Software and Compiler Design

27

Output : $ sh 1a.sh 1 2 3 number of arguments are : 3 3 2 1 $ ./1a.sh rahul raj rani number of arguments are : 3 rani raj rahul Explanation : The special shell parameters $# holds the number of arguments passed in the command line .Assume you are passing three arguments X Y Z .So $# value will be 3. The while loop does the operation still control command returns a true exit status. The use of eval command makes the shell to scan the command line once more, that is, second time and then actually executes the command line. Here because of metacharacter \ the first $ is overlooked and the next variable $len is gets evaluated resulting 3. After this evaluation the statement will be equivalent to echo $3. So the positional parameter $3 value is displayed and so on the remaining positional parameter value is displayed. While evaluating the expression the operands must be enclosed on either side by whitespace. 1. b) C program that creates a child process to read commands from the standard input and execute them ( a minimal implementation of a shell like a program). You can assume that no arguments will be passed to the commands to be executed.

Filename : 1b.c #include<stdio.h> #include<sys/types.h> int main() { char cmd[20]; pid_t pid; int ch; pid=fork(); if(pid == 0) { do { printf("\n Enter the command to be executed : "); scanf("%s",cmd);

28

System Software and Compiler Design

system(cmd); printf("\n Enter 1 to continue and 0 to exit : "); scanf("%d",&ch); } while(ch!=0); } wait(); } Output : $ cc 1b.c $ ./a.out Enter the command to be executed : date wed Dec 16 11:05:52 IST 2009 Enter 1 to continue and 0 to exit : 1 Enter the command to be executed : cal December 2009 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Explanation : All processes in a UNIX system ,expect the very first process (Process 0) which is created by the system boot code and remaining are created via the fork system call. is : The fork system call is used to create a child process .The function prototype of fork

#include <unistd.h> pid_t fork(void); Returns : 0 in child, process ID of child in parent, -1 on error The new process created by fork is called the child process. This function is called once but returns twice. The only difference in the returns is that the return value in the child is 0, whereas the return value in the parent is the process ID of the new child. The reason the childs process ID is returned to the parent is that a process can have more than one child, and there is no function that allows a process to obtain the process IDs of its children. The reason fork returns 0 to the child is that a process can have only a single parent, and the child can always call getppid to obtain the process ID of its parent. (Process ID 0 is reserved for use by the kernel, so its not possible for 0 to be the process ID of a child.)

System Software and Compiler Design

29

System function The system function allows the users to access the standard output or standard input of the executed command. The function prototype of system function. #include <stdlib.h> int system(const char *smdstring); Returns : See below If cmdstring is a null pointer, system returns nonzero only if a command processor is available. Because system is implemented by calling fork, exec, and waitpid, there are three types of return values. 1. 2. 3. If either the fork fails or waitpid returns an error other than EINTR, system returns 1 with errno set to indicate the error. If the exec fails, implying that the shell cant be executed, the return value is as if the shell had executed exit(127). Otherwise, all three functions fork, exec, and waitpidsucceed, and the return value from system is the termination status of the shell, in the format specified for waitpid.

Wait function When a process terminates, either normally or abnormally, the kernel notifies the parent by sending the SIGCHLD signal to the parent. Because the termination of a child is an asynchronous event it can happen at any time while the parent is running this signal is the asynchronous notification from the kernel to the parent. The parent can choose to ignore this signal, or it can provide a function that is called when the signal occurs: a signal handler. The default action for this signal is to be ignored. So we need to be aware that a process that calls wait .The function prototype of wait function #include <sys/wait.h> pid_t wait(int *statloc); Return : process ID, or 1 on error 2. a) Shell script that accepts two file names as arguments, checks if the permissions of these files are identical and if the permissions are identical, outputs the common permission, otherwise outputs each file name followed by its permission.

Filename : 2a.sh ls -l $1 | cut c 1-10 > file1per ls -l $2 | cut -c 1-10 > file2per if cmp file1per file2per then echo "Both the files have same permission" cat file1per else

30

System Software and Compiler Design

echo "Both the files have different permission" echo "The permission of first file $1 is " cat file1per echo "The permission of second file $2 is " cat file2per fi Output : $cat > file1 this is first file content $cat > file2 this is second file content $sh 2a.sh file1 file2 Both the files have same permission -rw-r--r-$chmod 777 file2 $sh 2a.sh file1 file2 file1per file2per differ: byte 4, line 1 Both the files have different permission The permission of first file file1 is -rw-r--r-The permission of second file file2 is -rwxrwxrwx Explanation : Listing the file attributes is done with ls - l (long) option. This option displays all the 7 attributes of a file - like its permission, links, owner, group owner, size, last modification time and filename. $ ls l total 45 -rw-rr-- 1 root root 65 Dec 16 10:89 input.txt To extract the specific field we need to use simple filter cut follows with .c option with a list of column numbers. Ranges can be specified using the hyphen. To extract the permission field we have use cut c - 1-10. Here we are using pipeline mechanism to redirect the output of ls - l to the simple filter cut. A pipe is general mechanism by using which ,the output of one program is redirected as the input to another program directly without using any temporary files in between. In pipeline , the command on the left of the | must use standard output and the one on the right must use standard input. 2. b) C program to create a file with 16 bytes of arbitary data from the beginning and another 16 bytes of arbitary data from an offset of 48. Display the file contents to demonstrate how the hole in file is handled.

System Software and Compiler Design

31

Filename : 2b.c #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main() { int fd; char buf1[]="Department of IS"; char buf2[]="Department of CS"; fd=creat("ise",0622); if(fd < 0) { printf("\n Error in creating file"); exit(0); } write(fd,buf1,16); lseek(fd,48,SEEK_SET); write(fd,buf2,16); exit(0); } Output : $cc 2b.c $./a.out $od -c ise 0000000 D 0000020 \0 \0 \0 * 0000060 D 0000100

e \0

p \0

a \0

r \0

t \0

m \0

e n t o \0 \0 \0 \0

f \0

I \0

S \0

Theoretical Explanation :
creat Function A new file can be created by calling the creat function. The function prototype of creat function #include <fcntl.h> int creat(const char *pathname, mode_t mode); Returns : file descriptor opened for write-only if OK, 1 on error write Function Data is written to an open file with the write function.

32

System Software and Compiler Design

#include <unistd.h> ssize_t write(int filedes, const void *buf, size_t nbytes); Returns: number of bytes written if OK, 1 on error lseek Function Every open file has an associated "current file offset," normally a non-negative integer that measures the number of bytes from the beginning of the file .Read and write operations normally start at the current file offset and cause the offset to be incremented by the number of bytes read or written. By default, this offset is initialized to 0 when a file is opened, unless the O_APPEND option is specified. An open files offset can be set explicitly by calling lseek. The function prototype of lseek function : #include <unistd.h> off_t lseek(int filedes, off_t offset, int whence); Returns: new file offset if OK, 1 on error The interpretation of the offset depends on the value of the whence argument. If whence is SEEK_SET, the files offset is set to offset bytes from the beginning of the file. If whence is SEEK_CUR, the files offset is set to its current value plus the offset. The offset can be positive or negative. If whence is SEEK_END, the files offset is set to the size of the file plus the offset. The offset can be positive or negative. a) Shell script that takes a valid directory names as as argument and recursively descends all the subdirectories, finds the maximum length of any file in that hierarchy and writes this maximum valut to the standard output.

3.

Filename : 3a.sh maxsize=`ls -lR $1 | grep '^-' | cut -c 38-43 | sort -n | tail -1` echo "The max size of the file in directort $1 is $maxsize bytes" Output : $ls -l total 12 -rwxr-xr-x -rwxr-xr-x -rwxrwxrwx

1 root 1 root 1 root

root root root

148 Mar 366 Mar 192 Mar

1 22:17 1a.sh 1 22:17 2a.sh 1 22:17 3a.sh

$ sh 3a.sh /root/6ise/unix The max size of the file in directort /root/6ise/unix is 366 bytes

System Software and Compiler Design

33

Explanation : To take the input from the user we have to use read statement with a variable. Recursively to descend all the files in list we need to use ls command with - R option.Also - l is used for long listing. The output of ls command is piped to a terminal using tee command ,as well as to a file. Then further it is piped to the simple filter cut . To extract specific column we need use .c option with a list of column numbers, delimited by a comma. To extract the filesize field we need to use the range 38-43. Then at last the output is redirected to an another file. To display the content of a file we can use cat command. Then the file content is sorted with respect to numerals using sort - n option. Then the sorted output is redirected to an another file. So the last line while have the maximum value ,we can extract that using the filter tail with -1 option from the file. 3. b) C program that accepts valid file names as coomand line arguments and for each of the arguments, prints the type of the file ( Regular file, directory file, character special file, block special file, symbolic link etc ..)

Filename : 3b.c #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main(int argc, char *argv[]) { int i; struct stat buf; for(i=1; i< argc; i++) { printf("%s: ", argv[i]); lstat(argv[i],&buf); if(S_ISREG(buf.st_mode)) printf("file is a regular file\n"); if(S_ISDIR(buf.st_mode)) printf("file is a directory file\n"); if(S_ISCHR(buf.st_mode)) printf("file is a character file\n"); if(S_ISBLK(buf.st_mode)) printf("file is a block file\n"); if(S_ISLNK(buf.st_mode)) printf("file is a symbolic link file\n"); } exit(0); }

34

System Software and Compiler Design

Output : $cc 3b.c $./a.out /root/6ise/3b.c /root/6ise/3b.c: file is a regular file $./a.out /root/6ise/3b.c /root/6ise /root/6ise/3b.c: file is a regular file /root/6ise: file is a directory file $./a.out /dev/tty /dev/tty: file is a character file Explanation : lstat Function #include <sys/stat.h> int lstat(const char *pathname, struct stat *buf); Return : 0 if OK, 1 on error Given a pathname, the stat function returns a structure of information about the named file. The fstat function obtains information about the file that is already open on the descriptor filedes. The lstat function is similar to stat, but when the named file is a symbolic link, lstat returns information about the symbolic link, not the file referenced by the symbolic link. The second argument is a pointer to a structure that we must supply. The function fills in the structure pointed to by buf. The definition of the structure can differ among implementations, but it could look like

struct stat { mode_t st_mode; /* file type & mode (permissions) */ ino_t st_ino; /* i-node number (serial number) */ dev_t st_dev; /* device number (file system) */ dev_t st_rdev; /* device number for special files */ nlink_t st_nlink; /* number of links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* size in bytes, for regular files */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last file status change */ blksize_t st_blksize; /* best I/O block size */ blkcnt_t st_blocks; /* number of disk blocks allocated */ };

System Software and Compiler Design

35

File Types Most files on a UNIX system are either regular files or directories, but there are additional types of files. The types are : 1. Regular file. The most common type of file, which contains data of some form. There is no distinction to the UNIX kernel whether this data is text or binary. Any interpretation of the contents of a regular file is left to the application processing the file. 2. Directory file. A file that contains the names of other files and pointers to information on these files. Any process that has read permission for a directory file can read the contents of the directory, but only the kernel can write directly to a directory file 3. Block special file. A type of file providing buffered I/O access in fixed-size units to devices such as disk drives. 4. Character special file. A type of file providing unbuffered I/O access in variablesized units to devices. All devices on a system are either block special files or character special files. 5. FIFO. A type of file used for communication between processes. Its sometimes called a named pipe. 6. Socket. A type of file used for network communication between processes. A socket can also be used for non-network communication between processes on a single host. 7. Symbolic link. A type of file that points to another file. The type of a file is encoded in the st_mode member of the stat structure. We can determine the file type with the macros shown in below .The argument to each of these macros is the st_mode member from the stat structure. File type macros in <sys/stat.h>

Macro S_ISDIR() S_ISCHR() S_ISBLK() S_ISFIFO() S_ISLNK() S_ISSOCK()

Type of file directory file character special file block special file pipe or FIFO symbolic link socket

4.

a)

Shell script that accepts file names specified as arguments and creates a shell script that contains this file as well as the code to recreate these files. Thus if the script generated by your script is executed,it would recreate the original files.

36

System Software and Compiler Design

Filename : 4a.sh echo #to bundle,sh this file for i in $* do echo "echo $i 1>&2" echo "cat >$i <<'End of $i'" cat $i echo "End of $i" done Output : $ls 10b.c 1b.c 4a.sh 5a.sh 5b.c 6a.sh 6b.c 7a.sh 8a.sh 9a.sh a $cat > file1 this is first file $cat > file2 this is second file $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 $sh 4a.sh file1 file2 > new.sh $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 new.sh $rm file1 rm: remove regular file `file1'? y $rm file2 rm: remove regular file `file2'? y $ls 10b.c 1b.c 4a.sh 5a.sh 5b.c 6a.sh 6b.c 7a.sh 8a.sh 9a.sh a new.sh $sh new.sh file1 file2 $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 new.sh $cat file1 this is first file $cat file2 this is second file

System Software and Compiler Design

37

4.

b)

C program to do the following. Using fork( ) create a child process. The child process prints its own process-id and id of its parent and then exits.The parent process waits for its child to finish(by executing wait( )) and prints its own process-id and the id of its child process and then exits.

Filename : 4b.c #include <sys/types.h> #include <stdio.h> int main() { pid_t pid; if((pid=fork())<0) printf("fork error"); if(pid==0) { printf("\n This is child process "); printf("\n Child PID :%d",getpid()); printf("\n Parent PID :%d\n",getppid()); exit(0); } else { wait(); printf("\n This is parent process"); printf("\n Parent PID :%d",getpid()); printf("\n Child PID :%d",pid); exit(0); } } Output : $cc 4b.c $./a.out This is child process Child PID :3122 Parent PID :3121 This is parent process Parent PID :3121 Child PID :3122 Explanation : Every process has a unique process ID, a non-negative integer. Because the process ID is the only well-known identifier of a process that is always unique, it is often used as a piece of other identifiers, to guarantee uniqueness. Process ID 0 is usually the

38

System Software and Compiler Design

scheduler process and is often known as the swapper. No program on disk corresponds to this process, which is part of the kernel and is known as a system process. Process ID 1 is usually the init process and is invoked by the kernel at the end of the bootstrap procedure. In addition to the process ID, there are other identifiers for every process. The following functions return these identifiers. #include <unistd.h> pid_t getpid(void); Returns : process ID of calling process pid_t getppid(void); Returns: parent process ID of calling process 5. Write a C program to implement the syntax directed definition of if E then S1 and if E then S1 else S2. /* Input to the program is assumed to be syntactically correct. The expression of if statement, statement for true condition and statement for false condition are enclosed in parenthesis */ #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> int parsecondition(char[],int,char*,int); void gen(char [],char [],char[],int); int main() { int counter = 0,stlen =0,elseflag=0; char stmt[60]; // contains the input statement char strB[54]; // holds the expression for 'if' condition char strS1[50]; // holds the statement for true condition char strS2[45]; // holds the statement for false condition clrscr(); printf("Format of if statement \n Example ...\n"); printf("if (a<b) then (s=a);\n"); printf("if (a<b) then (s=a) else (s=b);\n\n"); printf("Enter the statement \n"); gets(stmt); stlen = strlen(stmt); counter = counter + 2; // increment over 'if'

System Software and Compiler Design

39

counter = parsecondition(stmt,counter,strB,stlen); if(stmt[counter]==')') counter++; counter = counter + 3; // increment over 'then' counter = parsecondition(stmt,counter,strS1,stlen); if(stmt[counter+1]==';') { // reached end of statement, generate the output printf("\n Parsing the input statement...."); gen(strB,strS1,strS2,elseflag); getch(); return 0; } if(stmt[counter]==')') counter++; // increment over ')' counter = counter + 3; // increment over 'else' counter = parsecondition(stmt,counter,strS2,stlen); counter = counter + 2; // move to the end of statement if(counter == stlen) { //generate the output elseflag = 1; printf("\n Parsing the input statement...."); gen(strB,strS1,strS2,elseflag); getch(); return 0; } return 0; } /* Function : parsecondition Description : This function parses the statement from the given index to get the statement enclosed in () Input : Statement, index to begin search, string to store the condition, total string length Output : Returns 0 on failure, Non zero counter value on success */ int parsecondition(char input[],int cntr,char *dest,int totallen) {

40

System Software and Compiler Design

int index = 0,pos = 0; while(input[cntr]!= '(' && cntr <= totallen) cntr++; if(cntr >= totallen) return 0; index = cntr; while (input[cntr]!=')') cntr++; if(cntr >= totallen) return 0; while(index<=cntr) dest[pos++] = input[index++]; dest[pos]='\0'; //null terminate the string return cntr; //non zero value } /* Function : gen () Description : This function generates three address code Input : Expression, statement for true condition, statement for false condition, flag to denote if the 'else' part is present in the statement output :Three address code */ void gen(char B[],char S1[],char S2[],int elsepart) { int Bt =101,Bf = 102,Sn =103; printf("\n\tIf %s goto %d",B,Bt); printf("\n\tgoto %d",Bf); printf("\n%d: ",Bt); printf("%s",S1); if(!elsepart) printf("\n%d: ",Bf); else { printf("\n\tgoto %d",Sn); printf("\n%d: %s",Bf,S2); printf("\n%d:",Sn); } } Output : Format of if statement Example ... if (a<b) then (s=a); if (a<b) then (s=a) else (s=b);

System Software and Compiler Design

41

Enter the statement if (a<b) then (s=a); Parsing the input statement.... If (a<b) goto 101 goto 102 101: (s=a) 102: Output : Format of if statement Example ... if (a<b) then (s=a); if (a<b) then (s=a) else (s=b); Enter the statement if (a<b) then (x=a) else (x=b); Parsing the input statement.... If (a<b) goto 101 goto 102 101: (x=a) goto 103 102: (x=b) 103: /* ALTERNATE PROGRAM To implement syntax directed translation of if-else statement */ #include <iostream> #include <string> #include <cstring> class SyntaxDirectedTranslator { public: // Input the ifelse statement... void input(); // Parse and extract the different parts...

42

System Software and Compiler Design

void parse(); // Generate the intermediate code... void generate(); private: std :: string ifelse; char expression[51] , statement1[51] , statement2[51]; };

// // // //

The if-else statement Expression part 'True' part 'False' part

int main ( int argc , char **argv ) { // Create a Translator... SyntaxDirectedTranslator SDT; // Input the statement... SDT.input(); // Parse... SDT.parse(); // Generate code... SDT.generate(); return 0; } void SyntaxDirectedTranslator :: input() { // Enter the statement... std :: cout << "Enter the if-else statement --\n" << "Example : if (expr) then (s1) else (s2)\n"; std :: getline ( std :: cin , ifelse , '\n' ); } void SyntaxDirectedTranslator :: parse() { // Skip the 'if' part... std :: size_t i = 0; while(ifelse[i] == ' ') ++i; i += 2; while(ifelse[i] == ' ') ++i;

System Software and Compiler Design

43

// Find the expression part... std :: size_t j = 0; while ( ifelse[i] != ')' ) expression[j++] = ifelse[i++]; expression[j++] = ifelse[i++]; expression[j] = '\0'; // Skip the 'then' part... while(ifelse[i] == ' ') ++i; i += 4; while(ifelse[i] == ' ') ++i; // Next, get the 'true' statement... j = 0; while ( ifelse[i] != ')' ) statement1[j++] = ifelse[i++]; statement1[j++] = ifelse[i++]; statement1[j] = '\0'; // Check if else part is there... while(ifelse[i] == ' ') ++i; if ( ifelse[i] == '\0' ) { statement2[0] = '\0'; return; } // Skip the else part... i += 4; while(ifelse[i] == ' ') ++i; // Get the 'false' part... j = 0; while ( ifelse[i] != ')' ) statement2[j++] = ifelse[i++]; statement2[j++] = ifelse[i++]; statement2[j] = '\0'; }

44

System Software and Compiler Design

void SyntaxDirectedTranslator :: generate() { // Output the generated code... std :: cout << " if " << expression << " goto 101\n" << " goto 102\n" << "101: " << statement1 << std :: endl; if ( strlen ( statement2 ) == 0 ) { std :: cout << "102: \n"; return; } std :: cout << " goto 103\n" << "102: " << statement2 << std :: endl << "103: "; } 6. Write a yacc program that accepts a regular expression as input and produce its parse tree as output

%{ #include<ctype.h> char str[20]; int i=0; %} %token id %left '+''/''*''-' %% E:S {infix_postfix(str);} S:S'+'T |S'-'T |T T:T'*'F| T'/'F |F F:id |'('S')' ; %%

#include<stdio.h> main() { printf("\nEnter an identifier:"); yyparse(); } yyerror()

System Software and Compiler Design

45

{ printf("invalid"); } yylex() { char ch=' '; while(ch!='\n') { ch=getchar(); str[i++]=ch; if(isalpha(ch)) return id; if(ch=='+'||ch=='*'|| ch=='-'||ch=='/') return ch; } str[--i]='\0'; return(0); exit(0); }

void push(char stack[],int *top,char ch) { stack[++(*top)]=ch; } char pop(char stack[],int *top) { return(stack[(*top)--]); } int prec(char ch) { switch(ch) { case '/': case '*': return 2; case '+': case '-': return 1; case '(': return 0; default: return -1; } }

46

System Software and Compiler Design

void infix_postfix(char infix[]) { int top=-1,iptr=-1,pptr=-1; char postfix[20],stack[20],stksymb,cursymb; push(stack,&top,'\0'); while((cursymb=infix[++iptr])!='\0') { switch(cursymb) { case '(' : push(stack,&top,cursymb); break; case ')' :stksymb=pop(stack,&top); while(stksymb!='(') { postfix[++pptr]=stksymb; stksymb=pop(stack,&top); } break; case '*' : case '/' : case '+' : case '-' : while(prec(stack[top])>=prec(cursymb)) postfix[++pptr]=pop(stack,&top); push(stack,&top,cursymb); break; default : if(isalnum(cursymb)==0) { printf("Error in input!"); exit(0);} postfix[++pptr]=cursymb; } } while(top!=-1) postfix[++pptr]=pop(stack,&top); printf("%s\n",postfix); } Output : Enter the identifier : a+b*c abc*+

System Software and Compiler Design

47

/* ALTERNATE PROGRAM Yacc program to recognise a regular expression and produce a parse tree as output */ %{ #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> /* To store the productions */ #define MAX 100 int getREindex ( const char* ); signed char productions[MAX][MAX]; int count = 0 , i , j; char temp[MAX + MAX] , temp2[MAX + MAX]; %} %token ALPHABET %left '|' %left '.' %nonassoc '*' '+' %% S : re '\n'

{ printf ( "This is the rightmost derivation--\n" ); for ( i = count - 1 ; i >= 0 ; --i ) { if ( i == count - 1 ) { printf ( "\nre => " ); strcpy ( temp , productions[i] ); printf ( "%s" , productions[i] ); } else { printf ( "\n => " ); j = getREindex ( temp ); temp[j] = '\0'; sprintf ( temp2 , "%s%s%s" , temp , productions[i] , (temp + j + 2) ); printf ( "%s" , temp2 ); strcpy ( temp , temp2 ); } } printf ( "\n" );

48

System Software and Compiler Design

exit ( 0 ); } re : ALPHABET { temp[0] = yylval; temp[1] = '\0'; strcpy ( productions[count++] , temp ); } | | | | | ; %% int main ( int argc , char **argv ) { /* Parse and output the rightmost derivation, from which we can get the parse tree */ yyparse(); return 0; } yylex() { signed char ch = getchar(); yylval = ch; if ( isalpha ( ch ) ) return ALPHABET; return ch; } yyerror() { fprintf ( stderr , "Invalid Regular Expression!!\n" ); exit ( 1 ); } int getREindex ( const int i = strlen ( str for ( ; i >= 0 ; --i if ( str[i] == 'e' return i-1; char *str ) { ) - 1; ) { && str[i-1] == 'r' ) '(' re ')'{ strcpy ( productions[count++] , "(re)" ); } re '*' { strcpy ( productions[count++] , "re*" ); } re '+' { strcpy ( productions[count++] , "re+" ); } re '|' re { strcpy ( productions[count++] , "re | re" ); } re '.' re { strcpy ( productions[count++] , "re . re" ); }

System Software and Compiler Design

49

} } Operators used | is for ORing . is for concatenating * is Kleene closure a+ is equivalent to a.a* C:\Prog6>a.out a+|b*|(b.c*) This is the rightmost derivation-re => => => => => => => => => => => re | re re | (re) re | (re . re) re | (re . re*) re | (re . c*) re | (b . c*) re | re | (b . c*) re | re* | (b . c*) re | b* | (b . c*) re+ | b* | (b . c*) a+ | b* | (b . c*)

C:\Prog6>a.out a.(b|(a+)) This is the rightmost derivation-re => => => => => => => => re . re re . (re) re . (re | re) re . (re | (re)) re . (re | (re+)) re . (re | (a+)) re . (b | (a+)) a . (b | (a+))

/* Some explanation of the code Yacc generates an LR parser. Because it is LR, it matches productions for the rightmost derivation in REVERSE order. These productions are stored in an array of strings. Once the whole regex expression is matched then the derivation is output in the correct order. While outputting we need to store the current sentential form in the string 'temp'. At each step the rightmost 're' is replaced with the next production. getREindex() returns the position of the rightmost 're'.*/

50

System Programming

SYSTEM PROGAMMING LABORATORY


PART A
Execution of the following programs using LEX : 1) a. Program to count the number of characters, words, spaces and lines in a given input file. b. 2) a. b. 3) 4) Program to count the numbers of comment lines in a given program. Also eliminate them and copy that program into separate file. Program to recognize a valid arithmetic expression and identify the identifiers and operators present. Print them separately. Program to recognize whether a given sentence is simple or compound.

Program to recognize and count the number of identifiers in a given input file. Execution of the following programs using YACC. : a. b. Program to recognize a valid arithmetic expression that uses operators +,- ,* and /. Program to recognize a valid variable, which starts with a letter, followed by any number of letters or digits. Program to evaluate an arithmetic expression involving operators +, -, * and . Program to recognize strings aaab, abbb, ab and a using the grammar (ambn, m>0, n>=0).

5)

a. b.

6)

Program to recognize the grammar (anb, n>=10).

PART B
1) a. Non-recursive shell script that accepts any number of arguments and prints them in a Reverse order, (For example, if the script is named rargs, then rargs A B C should produce C B A on the standard output). C program that creates a child process to read commands from the standard input and execute them (a minimal implementation of a shell like program). You can assume that no arguments will be passed to the commands to be executed. Shell script that accepts two file names as arguments, checks if the permissions for these files are identical and if the permissions are identical, outputs the common permissions, otherwise outputs each file name followed by its permissions.

b.

2)

a.

System Programming

51

b.

C program to create a file with 16 bytes of arbitrary data from the beginning and another 16 bytes of arbitrary data from an offset of 48. Display the file contents to demonstrate how the hole in file is handled. Shell function that takes a valid directory names as an argument and recursively descends all the subdirectories, finds the maximum length of any file in that hierarchy and writes this maximum value to the standard output. Write a C program which accepts valid file names as command line arguments and for each of the arguments, prints the type of the file (regular file, directory file, character special file, block file, symbolic link etc.). Shell script that accepts path names and creates all the components in that path names as directories. For example, if the script name is mpe, then the command mpe a/b/c/d should create directories a, a/b, a/b/c and a/b/c/d. C program that accepts one command-line argument, executes the arguments as a shell command, determines the time taken by it and prints the time values, Use the times, function and the tms structure. The code need not include error checking. Shell script that accepts valid log-in names as arguments and prints their corresponding home directories. If no arguments are specified, print a suitable error message. C program that accepts valid directory names as a command line argument and lists all the files in the given directory as well as all the subsequent subdirectories. (The solution can be recursive or non-recursive). Shell script to implement terminal locking. It should prompt the user for a password. After accepting the password entered by the user, it must prompt again for password confirmation (to retype the password). If a match occurs, it must lock the terminal and prompt for a password. If the proper password is entered, the terminal must be unlocked. Note the script must be written to disregard BREAK, Control-D etc. No time limit need be implemented for the lock duration. Write a C program to prompt user for the name of an environment variable and print its value if it is defined and a suitable message otherwise; and to repeat the process if user wants it. Shell script that accepts file names specified as arguments and creates a shell script that contains this file as well as the code to recreate these files. Thus if the script generated by your script is executed, it would recreate the original files (This is same as the bundle script described by Brain W. Kernighan and Rob Pike in The Unix Programming Environment, Prentice Hall India). Awk script to delete duplicate lines in a file. The order of original lines must not change.

3)

a.

b.

4)

a.

b.

5)

a.

b.

6)

a.

b.

7)

a.

b.

52
8)

System Programming

a.

Shell script to find and display all the links of a file specified as the first argument to the script. The second argument, which is optional, can be used to specify the directory in which the search is to begin. If this second argument is not present, the search is to begin in current working directory. In either case, the starting directory as well as its subdirectories at all levels must be searched. The script need not include any error checking. PERL script that echoes its command line arguments, one per line after translating all lower case letters to upper case. Shell script to display the calendar for current month with current date replaced by * or ** depending on whether date has one digit or two digits. PERL program to convert unsigned binary number (supplied as argument) to decimal (for example if the argument is 10110 the output should be 22). If an argument is present, it can be a valid binary number and if no argument is present, the program should display an error message. Awk script that folds long line into 40 columns. Thus any line that exceeds 40 Characters must be broken after 40th and is to be continued with the residue. The inputs to be supplied through a text file created by the user. C program to do the following using fork () create a child process. The child process prints its own process id and id of its parent and then exits. The parent process waits for its child to finish (by executing the wait ()) and prints its own process id and the id of its child process and then exits.

b. 9) a. b.

10) a.

b.

Note Part A,LEX and YACC Programs are same as given and explained in SYSTEM SOFTWARE AND COMPILER DESIGN LABORATORY

PART B
UNIX PROGRAMMING
1. a) Non-recursive shell script that accepts any number of arguments and prints them in the reverse order.

Filename : 1a.sh echo "number len=$# while [ $len do eval echo len=`expr done of arguments are : $#" -ne 0 ] \$$len $len - 1`

System Programming

53

Output : $ sh 1a.sh 1 2 3 number of arguments are : 3 3 2 1 $ ./1a.sh rahul raj rani number of arguments are : 3 rani raj rahul 1. b) C program that creates a child process to read commands from the standard input and execute them ( a minimal implementation pf a shell like a program). You can assume that no arguments will be passed to the commands to be executed.

Filename : 1b.c #include<stdio.h> #include<sys/types.h> int main() { char cmd[20]; pid_t pid; int ch; pid=fork(); if(pid == 0) { do { printf("\n Enter the command to be executed : "); scanf("%s",cmd); system(cmd); printf("\n Enter 1 to continue and 0 to exit : "); scanf("%d",&ch); } while(ch!=0); } wait(); } Output : $ cc 1b.c

54

System Programming

$ ./a.out Enter the command to be executed : date wed Dec 16 11:05:52 IST 2009 Enter 1 to continue and 0 to exit : 1 Enter the command to be executed : cal December 2009 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 2. a) Shell script that accepts two file names as arguments, checks if the permissions of these files are identical and if the permissions are identical, outputs the common permission, otherwise outputs each file name followed by its permission.

Filename : 2a.sh ls -l $1 | cut c 1-10 > file1per ls -l $2 | cut -c 1-10 > file2per if cmp file1per file2per then echo "Both the files have same permission" cat file1per else echo "Both the files have different permission" echo "The permission of first file $1 is " cat file1per echo "The permission of second file $2 is " cat file2per fi Output : $cat > file1 this is first file content $cat > file2 this is second file content $sh 2a.sh file1 file2 Both the files have same permission -rw-r--r-$chmod 777 file2

System Programming

55

$sh 2a.sh file1 file2 file1per file2per differ: byte 4, line 1 Both the files have different permission The permission of first file file1 is -rw-r--r-The permission of second file file2 is -rwxrwxrwx 2. b) C program to create a file with 16 bytes of arbitary data from the beginning and another 16 bytes of arbitary data from an offset of 48. Display the file contents to demonstrate how the hole in file is handled

Filename : 2b.c #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main() { int fd; char buf1[]="Department of IS"; char buf2[]="Department of CS"; fd=creat("ise",0622); if(fd < 0) { printf("\n Error in creating file"); exit(0); } write(fd,buf1,16); lseek(fd,48,SEEK_SET); write(fd,buf2,16); exit(0); } Output : $cc 2b.c $./a.out $od -c ise 0000000 D 0000020 \0 \0 \0 * 0000060 D 0000100

e \0

p \0

a \0

r \0

t \0

m \0

e \0

n \0

t \0

\0

o \0

f I S \0 \0

56
3.

System Programming

a)

Shell script that takes a valid directory names as as argument and recursively descends all the subdirectories, finds the maximum length of any file in that hierarchy and writes this maximum valut to the standard output.

Filename : 3a.sh maxsize=`ls -lR $1 | grep '^-' | cut -c 38-43 | sort -n | tail -1` echo "The max size of the file in directort $1 is $maxsize bytes" Output : $ls -l total 12 -rwxr-xr-x 1 root root 148 Mar 1 22:17 1a.sh -rwxr-xr-x 1 root root 366 Mar 1 22:17 2a.sh -rwxrwxrwx 1 root root 192 Mar 1 22:17 3a.sh $ sh 3a.sh /root/6ise/unix The max size of the file in directort /root/6ise/unix is 366 bytes 3. b) C program that accepts valid file names as coomand line arguments and for each of the arguments, prints the type of the file ( Regular file, directory file, character special file, block special file, symbolic link etc ..)

Filename : 3b.c #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main(int argc, char *argv[]) { int i; struct stat buf; for(i=1; i< argc; i++) { printf("%s: ", argv[i]); lstat(argv[i],&buf); if(S_ISREG(buf.st_mode)) printf("file is a regular file\n"); if(S_ISDIR(buf.st_mode)) printf("file is a directory file\n"); if(S_ISCHR(buf.st_mode)) printf("file is a character file\n");

System Programming

57

if(S_ISBLK(buf.st_mode)) printf("file is a block file\n"); if(S_ISLNK(buf.st_mode)) printf("file is a symbolic link file\n"); } exit(0); } Output : $cc 3b.c $./a.out /root/6ise/3b.c /root/6ise/3b.c: file is a regular file $./a.out /root/6ise/3b.c /root/6ise /root/6ise/3b.c: file is a regular file /root/6ise: file is a directory file $./a.out /dev/tty /dev/tty: file is a character file 4. a) Write a shell script that accepts path names and creates all the components in that path names as directories. For example, if the script is mpe, then the command mpe a/b/c/d should create directories a, a/b, a/b/c and a/b/c/d.

Filename : 4a.sh if [ $# -le 0 o $# -gt 1 ] then echo Improper Usage : pathname required else mkdir -p $1 fi Output : $ $ $ b $ $ C $ $ d sh 4a.sh a/b/c/d cd a ls cd b ls cd c ls

58
4.

System Programming

b)

Write a C program that accepts one command-line argument, executes the arguments as shell command, determines the time taken by it and prints the time values, Use the times, function and the tms structure. The code need not include error checking.

Filename : 4b.c #include<stdio.h> #include<sys/times.h> #include<unistd.h> #include<time.h> int main(int argc, char *argv[]) { struct tms tms1,tms2; clock_t begin,end; long clktick = sysconf(_SC_CLK_TCK); begin=times(&tms1); system(argv[1]); end=times(&tms2); printf("\n\t Time taken is %f ",(end-begin)/(double)CLK_TCK); printf("\n\t Time taken is %f ",(tms2.tms_utimetms1. tms_utime)/(double)clktick); } Output : $ cc 4b.c $./a.out ls 1a.l 1b.l 2a.l 2b.l 3.l 4a.l 4a.y 4b.l 4b.y 5a.l 5b.y 6 1a.sh 2a.sh 3a.sh 4a.sh 1b.c 2b.c 3b.c 4b.c ./a.out Time taken is 0.010000 Time taken is 0.000000 $ ./a.out cal December 2009 Su Mo Tu 1 6 7 8 13 14 15 20 21 22 27 28 29

We 2 9 16 23 30

Th 3 10 17 24 31

Fr 4 11 18 25

Sa 5 12 19 26

Time taken is 0.020000 Time taken is 0.000000

System Programming

59

5.

Shell script that accepts valid log-in names as arguments and prints their corresponding home directories. If no arguments are specified, print a suitable error message. Filename : 5a.sh if [ $# -lt 1 ] then echo " Invalid Arguments....... " exit fi for x in "$@" do if grep "$x" /etc/passwd > file1 then echo" The login name is : $x" echo " The Home directory is : `cut -d ":" -f 6 file1`" else echo " $x is not a valid login name " fi done Output : $ sh 5a.sh cse The login name is : cse The Home directory is : /home/cse $ sh 5a.sh Invalid Arguments....... 5. C program that accepts valid directory names as a command line argument and lists all the files in the given directory as well as all the subsequent subdirectories. (The solution can be recursive or non-recursive). Filename : 5b.c #include<stdio.h. #include<string.h> int main(int argc, char *argv[]) { int i; char str[50]; for(i=1;i<argc;i++) { strcpy(str, ls R ); /* leave space after R */ strcat(str,argv[i]); system(str); } } b)

a)

60

System Programming

Output : $ cc 5b.c $ ./a.out /home/ise 1a.l 1b.l 2a.l 2b.l 3.l 4a.l 4a.y 4b.l 4b.y 5a.l 5b.y 6 1a.sh 2a.sh 3a.sh 4a.sh 1b.c 2b.c 3b.c 4b.c ./a.out a /home/ise/a: b /home/ise/a/b: c /home/ise/a/b/c: d /home/ise/a/b/c/d: 6. a) Shell script to implement terminal locking. It should prompt the user for a password. After accepting the password entered by the user, it must prompt again for password confirmation (to retype the password). If a match occurs, it must lock the terminal and prompt for a password. If the proper password is entered, the terminal must be unlocked. Note the script must be written to disregard BREAK, Control-D etc. No time limit need be implemented for the lock duration.

Filename : 6a.sh trap "" 1 2 3 5 20 clear echo -e "Enter password to lock terminal:" stty -echo read keynew stty echo echo -e "Confirm password:" stty -echo read keyold stty echo if [ $keyold = $keynew ] then echo "Terminal locked!" while [ 1 ] do echo "Retype the password to unlock:" stty -echo read key if [ $key = $keynew ] then

System Programming

61

stty echo echo "Terminal unlocked!" stty sane exit fi echo "Invalid password!" done else echo " Passwords do not match!" fi stty sane Output : $ sh 6a.sh Enter password to lock terminal: Confirm password: Terminal locked! Retype the password to unlock: Invalid password! Retype the password to unlock: Invalid password! Retype the password to unlock: Terminal unlocked! $ sh 6a.sh Enter password to lock terminal: Confirm password: Passwords do not match! 6. b) Write a C program to prompt user for the name of an environment variable and print its value if it is defined and a suitable message otherwise; and to repeat the process if user wants it.

Filename : 6b.c #include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<stdlib.h> int main( ) { char name[25]; int i; char *p; do

62

System Programming

{ printf(\n Enter any environment variable :); scanf(%s,name); p=getenv(name); if(p) printf(%s,p); else printf(\n Environment variable not defined); printf(\n Want to continue 1-yes 0-no :\n); scanf(%d,&i); } while(i!=0); } Output : $ cc 6b.c $ ./a.out Enter any environment variable :HOME Root Want to continue 1-yes 0-no :0 7. a) Shell script that accepts file names specified as arguments and creates a shell script that contains this file as well as the code to recreate these files. Thus if the script generated by your script is executed, it would recreate the original files (This is same as the bundle script described by Brain W. Kernighan and Rob Pike in The Unix Programming Environment, Prentice Hall India).

Filename : 7a.sh echo #to bundle,sh this file for i in $* do echo "echo $i 1>&2" echo "cat >$i <<'End of $i'" cat $i echo "End of $i" done Output : $ls 10b.c 1b.c 4a.sh 5a.sh a $cat > file1 this is first file

5b.c

6a.sh

6b.c

7a.sh

8a.sh

9a.sh

System Programming

63

$cat > file2 this is second file $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 $sh 7a.sh file1 file2 > new.sh $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 new.sh $rm file1 rm: remove regular file `file1'? y $rm file2 rm: remove regular file `file2'? y $ls 10b.c 1b.c 4a.sh 5a.sh 5b.c 6a.sh 6b.c 7a.sh a new.sh $sh new.sh file1 file2 $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 new.sh $cat file1 this is first file $cat file2 this is second file 7. b)

8a.sh

9a.sh

Awk script to delete duplicate lines in a file. The order of original lines must not change.

Filename : 7b.awk { found=0 for(i=0;i<nlines;i++) if(lines[i] == $0) { found=1 break } if(!found) { lines[nlines++]=$0 print $0 } }

64

System Programming

Output : $ vi sample.txt ise cse ise ec tc cse $ awk f 7b.awk sample.txt ise cse ec tc 8. a) Shell script to find and display all the links of a file specified as the first argument to the script. The second argument, which is optional, can be used to specify the directory in which the search is to begin. If this second argument is not present, he search is to begin in current working directory. In either case, the starting directory as well as its subdirectories at all levels must be searched. The script need not include any error checking.

Filename : 8a.sh if [ $# -eq 0 ] then echo "Usage:sh 8a.sh[file1] [dir1(optional)]" exit fi if [ -f $1 ] then dir="." if [ $# -eq 2 ] then dir=$2 fi str=`ls -i $1|cut -d " " -f 1` echo "Hard links of $1 are" find $dir -inum $str -print echo "Soft links of $1 are" find $dir -lname $1 -print else echo "The file $1 does not exist" fi

System Programming

65

Output : $ vi file1 $ ln s file1 file2 $ ln file1 file3 $ ln file1 file4 $ sh 8a.sh file1 Hard links of file1 are file3 file4 Soft links of file1 are file2 8. b) PERL script that echoes its command line arguments, one per line after translating all lower case letters to upper case.

Filename : 8b.pl foreach $string (@ARGV) { $string=~tr/a-z/A-Z/; print($string\n); } Output : $perl 8b.pl unix system programming UNIX SYSTEM PROGRAMMING 9. a) Shell script to display the calendar for current month with current date replaced by * or ** depending on whether date has one digit or two digits.

Filename : 9a.sh cal > dayno set `date` x=$3 if [ $x le 9 ] then sed s/ $3 / */ dayno else sed s/ $3/ **/ dayno fi rm dayno

66

System Programming

Output : $ sh 9a.sh December 2009 Su Mo Tu 1 6 7 8 13 14 15 20 21 22 27 28 29 9. b)

We 2 9 ** 23 30

Th 3 10 17 24 31

Fr 4 11 18 25

Sa 5 12 19 26

PERL program to convert unsigned binary number (supplied as argument) to decimal (for example if the argument is 10110 the output should be 22). If an argument is present, it can be a valid binary number and if no argument is present, the program should display an error message.

Filename : 9b.pl if(@ARGV==0) { print(Invalid arguments); } else { $num=0; $mul=1; while($ARGV[0] != ) { $num = $num + chop($ARGV[0]) * $mul; $mul = $mul * 2; } print($num\n); } Output : $ perl 9b.pl 101 5 $ perl 9b.pl 111 7 $ perl 9b.pl Invalid arguments 10) a. Awk script that folds long line into 40 columns. Thus any line that exceeds 40 Characters must be broken after 40th and is to be continued with the residue. The inputs to be supplied through a text file created by the user.

System Programming

67

Filename : 10a.awk { x=$0 while(length(x) > 40) { printf(%sX\n,substr(x,1,40)) x=substr(x,41,length(x)-40) } print(%s\n,x); } Output : $vi abc.txt Signals are software interrupts. UNIX uses signals to inform a process of asynchronous events and to handle exception. Signals provide a mechanism for notifying process of systems events. For example, when a user types control C at the terminal. $awk -f 10a.awk abc.tzt Signals are software interrupts. UNIX usX es signals to inform a process of asynchX ronous events and to handle exception. SX ignals provide a mechanism for notifyingX process of systems events. For example,X when a user types control C at the termX inal. 10. b) C program to do the following using fork () create a child process. The child process prints its own process id and id of its parent and then exits. The parent process waits for its child to finish (by executing the wait ()) and prints its own process id and the id of its child process and then exits.

Filename : 10b.c #include <sys/types.h> #include <stdio.h> int main() { pid_t pid; if((pid=fork())<0) printf("fork error"); if(pid==0)

68

System Programming

{ printf("\n This is child process "); printf("\n Child PID :%d",getpid()); printf("\n Parent PID :%d\n",getppid()); exit(0); } else { wait(); printf("\n This is parent process"); printf("\n Parent PID :%d",getpid()); printf("\n Child PID :%d",pid); exit(0); } } Output : $cc 10b.c $./a.out This is child process Child PID :3122 Parent PID :3121 This is parent process Parent PID :3121 Child PID :3122

File Structures

69

FILE STRUCTURES LABORATORY


1. Write a C++ program to read series of names, one per line, from standard input and write these names spelled in reverse order to the standard output using I/O redirection and pipes. Repeat the exercise using an input file specified by the user instead of the standard input and using an output file specified by the user instead of the standard output. Write a C++ program to read and write and student objects with fixed length records and the fields delimited by |.implement pack(),unpack(),modify() and search() methods. Write a C++ program to read and write and student objects with variable length records using any suitable record structure. Implement pack(),unpack(),modify() and search() methods Write a c++ program to write student objects with variable-length records using any suitable record structure and to read from this file a student record using RRN. Write a C++ program to implement simple index on primary key for a file of student objects. Implement add(),search(),delete() using the index. Write a C++ program to implement index on secondary key, the name, for a file of student objects. Implement add(),search(),delete() using the secondary index. Write a C++ program to read two lists of names and then match the names in the two lists using Consequential Match based on a single loop. Output the names common to both the lists. Write a C++ program to read k Lists of names and merge them using kway merge algorithm with k = 8. Write a C++ program to implement B-Tree for a given set of integers and its operations insert ( ) and search ( ). Display the tree.

2.

3.

4.

5. 6.

7.

8. 9.

10. Write a C++ program to implement B+ tree for a given set of integers and its operations insert ( ), and search ( ). Display the tree. 11. Write a C++ program to store and retrieve student data from file using hashing. Use any collision resolution technique 12. Write a C++ program to reclaim the free space resulting from the deletion of records using linked lists.

70
1.

File Structures

Write a C++ program to read series of names, one per line, from standard input and write these names spelled in reverse order to the standard output using I/O redirection and pipes. Repeat the exercise using an input file specified by the user instead of the standard input and using an output file specified by the user instead of the standard output.

Filename : fs1.cpp #include<iostream.h> #include<fstream.h> #include<conio.h> #include<string.h> void swap(char &x,char &y) { char temp=x; x=y; y=temp; } void reverse(char *name) { int count=strlen(name); for(int i=0,j=count-1;i<count/2;++i,--j) swap(name[i],name[j]); } void main(int argc,char *argv[]) { if(argc==1) { char name[10]; do { cin>>name; reverse(name); cout<<name<<endl; if(cin.eof()) break; }while(1); } else if(argc>2) { char name[20]; fstream fd1,fd2; fd1.open(argv[1],ios::in);

File Structures

71

fd2.open(argv[2],ios::out|ios::app|ios::trunc); do { fd1>>name; reverse(name); cout<<name; fd2<<name<<endl; if(fd1.eof()) break; }while(1); fd1.close(); fd2.close(); } cout<<"usage:"<<argv[0]<<"filename1 filename2"; } Output: C:\TC\BIN>FS1.exe networks skrowten file elif system metsys C:\TC\BIN>edit input networks files system compiler graphics C:\TC\BIN>FS1.exe input output skrowtenselifmetsysrelipmocscihparg C:\TC\BIN>type output skrowten selif metsys relipmoc scihparg C:\TC\BIN>FS1.EXE INPUT usage:FS1.EXE filename1 filename2

72
2.

File Structures

Write a C++ program to read and write and student objects with fixed-length records and the fields delimited by |.implement pack(),unpack(),modify() and search() methods.

#include<stdio.h> #include<stdlib.h> #include<iostream.h> #include<fstream.h> #include<conio.h> #include<string.h> #include<iomanip.h> class student { public: name[15],usn[15],age[5],sem[5],branch[15],buffer[45]; }; student s2[100]; void writeRecord() //Function to add record to file { fstream app; student s; app.open("student.txt",ios::app); //Open file in append mode if(!app) { cout<<"cannot open the file in output mode"; getch(); exit(0); } cout<<"\n Enter the student name = "; cin>>s.name; cout<<"\n Enter the usn = "; cin>>s.usn; cout<<"\n Enter the age = "; cin>>s.age; cout<<"\n Enter the sem = "; cin>>s.sem; cout<<"\n Enter the branch = "; cin>>s.branch; //packing the information strcpy(s.buffer, s.name); strcat(s.buffer,"|"); strcat(s.buffer, s.usn); strcat(s.buffer,"|"); strcat(s.buffer, s.age); strcat(s.buffer,"|"); strcat(s.buffer, s.sem); strcat(s.buffer,"|"); strcat(s.buffer, s.branch); int count=strlen(s.buffer); char

File Structures

73

for(int k=0;k<45-count;k++) strcat(s.buffer,"!"); strcat(s.buffer,"\n"); app<<s.buffer; //writing the packed information to buffer app.close(); } void search() { fstream in; char usn[15], extra[45]; in.open("student.txt",ios::in); if(!in) { cout<<"\nUnable to open the file in input mode"; getch(); exit(0); } cout<<"\nEnter the record's usn you want to search = cin>>usn; student s; //Unpacking the record while(!in.eof()) { in.getline(s.name,15,'|'); in.getline(s.usn,15,'|'); in.getline(s.age,5,'|'); in.getline(s.sem,5,'|'); in.getline(s.branch,15,'|'); in.getline(extra,45,'\n'); if(strcmp(s.usn,usn)==0) { cout<<"\nRecord found"; cout<<"\n"<<s.name<<"\t"<<s.usn<<"\t"<<s.age<<"\t"<<s.sem<<"\t"<<s.branch; getch(); return; } } cout<<"\n Record not found"; getch(); return; }

";

74

File Structures

void displayFile() { student s; int c,i; char extra[45]; fstream in; in.open("student.txt",ios::in); if(!in) { cout<<"\nCannot open the file in output mode"; getch(); exit(0); } i=0; printf("Name\t\tUsn\t\tAge\t\tSem\t\tBranch\n"); while(!in.eof()) { in.getline(s.name,15,'|'); in.getline(s.usn,15,'|'); in.getline(s.age,5,'|'); in.getline(s.sem,5,'|'); in.getline(s.branch,15,'!'); in.getline(extra,45,'\n'); printf("\n%s\t\t%s\t\t%s\t\t%s\t\t%s",s.name,s.usn,s.age,s.sem,s.branch); i++; } in.close(); getch(); } void modify() { fstream in; char usn[15],buffer[45],extra[45]; int i,j; student s1[100]; in.open("student.txt",ios::in); if(!in) { cout<<"\nUnable to open the file in input mode"; getch(); exit(0); } cout<<"\nEnter the usn"; cin>>usn;

File Structures

75

i=0; //Loading the file to Main memory while(!in.eof()) { in.getline(s1[i].name,15,'|'); in.getline(s1[i].usn,15,'|'); in.getline(s1[i].age,5,'|'); in.getline(s1[i].sem,5,'|'); in.getline(s1[i]. branch, 15,'\n'); in.getline(extra,45,'\n'); i++; } i--; for(j=0;j<i;j++) { if(strcmp(usn,s1[j].usn)==0) { cout<<"\nThe old values of the record with usn "<<usn<<" are "; cout<<"\nname cout<<"\nusn cout<<"\nage cout<<"\nsem cout<<"\nbranch = = = = = "<< "<< "<< "<< "<< s1[j].name; s1[j].usn; s1[j].age; s1[j].sem; s1[j].branch;

cout<<"\nEnter the new values \n"; cout<<"\nname = "; cin>>s1[j].name; cout<<"\nusn = "; cin>>s1[j].usn; cout<<"\nage = "; cin>>s1[j].age; cout<<"\nsem = "; cin>>s1[j].sem; cout<<"\nbranch= "; cin>>s1[j].branch; break; } } if(j==i) { cout<<"\n Record with usn "<<usn<<" is not present"; getch(); return; } in.close(); fstream out1; out1.open("student.txt",ios::out); if(!out1) { cout<<"\nUnable to open file in output mode";

76

File Structures

getch(); return; } for(j=0;j<i;j++) { strcpy(buffer,s1[j].name); strcat(buffer,"|"); strcat(buffer,s1[j].usn); strcat(buffer,"|"); strcat(buffer,s1[j].age); strcat(buffer,"|"); strcat(buffer,s1[j].sem); strcat(buffer,"|"); strcat(buffer,s1[j].branch); int count=strlen(buffer); for(int k=0;k<45-count;k++) strcat(buffer,"!"); strcat(buffer,"\n"); out1<<buffer; } out1.close(); } void main() { fstream in; fstream out; int ch; out.open("student.txt",ios::out); if(!in) { cout<<"\n\nCannot open the file in output mode"; getch(); exit(0); } out.close(); for(;;) { clrscr(); cout<<"\n 1: write to file\n 2:display the file" <<"\n 3:modify the file\n 4:search\n 5.exit"; cout<<"\n\n Enter the choice: "; cin>>ch; switch(ch) { case 1: writeRecord();break; case 2: displayFile();break; case 3: modify();break;

File Structures

77

case 4: search (); break; case 5: exit(0); default: cout<<"\nInvalid input....";break; } } } Output : 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = ajay usn = 1vk07is002 age = 20 sem = 6 branch = ise

1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = rahul usn = 1vk07cs045 age = 20 sem = 6 branch = cse

1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:2 Name Usn Age

Sem

Branch

78

File Structures

ajay rahul

1vk07is002 20 1vk07cs045 20

6 6

ise!!!!!!!!!!! cse!!!!!!!!!!!

1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:4 Enter the record's usn you want to search = 1vk07cs045 Record found rahul 1vk07cs045 20 6 cse!!!!!!!!!!! 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:5 C:\TC|BIN>type student.txt ajay|1vk07is002|20|6|ise!!!!!!!!!!! rahul|1vk07cs045|20|6|cse!!!!!!!!!!! 3. Write a C++ program to read and write and student objects with variable length records using any suitable record structure. Implement pack(),unpack(),modify() and search() methods

#include<stdio.h> #include<stdlib.h> #include<iostream.h> #include<fstream.h> #include<conio.h> #include<string.h> #include<iomanip.h> class student { public: char name[15], buffer[100]; }; student s2[100];

usn[15],

age[5],

sem[5],

branch[15],

File Structures

79

void writeRecord() { fstream app; student s; app.open("student.txt",ios::app); //Open file in append mode if(!app) { cout<<"cannot open the file in output mode"; getch(); exit(0); } cout<<"\n Enter the student name = "; cin>>s.name; cout<<"\n Enter the usn = "; cin>>s.usn; cout<<"\n Enter the age = "; cin>>s.age; cout<<"\n Enter the sem = "; cin>>s.sem; cout<<"\n Enter the branch = "; cin>>s.branch; //packing the information strcpy(s.buffer, s.name); strcat(s.buffer,"|"); strcat(s.buffer, s.usn); strcat(s.buffer,"|"); strcat(s.buffer, s.age); strcat(s.buffer,"|"); strcat(s.buffer, s.sem); strcat(s.buffer,"|"); strcat(s.buffer, s.branch);strcat(s.buffer,"\n"); app<<s.buffer; app.close(); } void search() { fstream in; char usn[15], extra[45]; in.open("student.txt",ios::in); if(!in) { cout<<"\nUnable to open the file in input mode"; getch(); exit(0); } cout<<"\nEnter the record's usn you want to search = cin>>usn; student s; //Unpacking the record while(!in.eof()) { //writing the packed information to buffer

";

80

File Structures

in.getline(s.name,15,'|'); in.getline(s.usn,15,'|'); in.getline(s.age,5,'|'); in.getline(s.sem,5,'|'); in.getline(s.branch,15,'\n'); if(strcmp(s.usn,usn)==0) { cout<<"\nRecord found"; cout<<"\n"<<s.name<<"\t"<<s.usn<<"\t"<<s.age<<"\t" <<s.sem<<"\t"<<s.branch; getch(); return; } } cout<<"\n Record not found"; getch(); return; } void displayFile() { student s; int c,i; fstream in; in.open("student.txt",ios::in); if(!in) { cout<<"\nCannot open the file in output mode"; getch(); exit(0); } i=0; printf("Name\t\tUsn\t\tAge\t\tSem\t\tBranch\n"); while(!in.eof()) { in.getline(s.name,15,'|'); in.getline(s.usn,15,'|'); in.getline(s.age,5,'|'); in.getline(s.sem,5,'|'); in.getline(s.branch,15,'\n'); printf("\n%s\t\t%s\t\t%s\t\t%s\t\t%s",s.name,s.usn, s.age,s.sem,s.branch); i++; } in.close(); getch(); }

File Structures

81

void modify() { fstream in; char usn[15],buffer[45],extra[45]; int i,j; student s1[100]; in.open("student.txt",ios::in); if(!in) { cout<<"\nUnable to open the file in input mode"; getch(); exit(0); } cout<<"\nEnter the usn"; cin>>usn; i=0; //Loading the file to Main memory while(!in.eof()) { in.getline(s1[i].name,15,'|'); in.getline(s1[i].usn,15,'|'); in.getline(s1[i].age,5,'|'); in.getline(s1[i].sem,5,'|'); in.getline(s1[i]. branch, 15,'\n'); i++; } i--; for(j=0;j<i;j++) { if(strcmp(usn,s1[j].usn)==0) { cout<<"\nThe old values of the record with usn "<<usn<<" are "; cout<<"\nname = "<< s1[j].name; cout<<"\nusn = "<< s1[j].usn; cout<<"\nage = "<< s1[j].age; cout<<"\nsem = "<< s1[j].sem; cout<<"\nbranch = "<< s1[j].branch; cout<<"\nEnter the new values \n"; cout<<"\nname = "; cin>>s1[j].name; cout<<"\nusn = "; cin>>s1[j].usn; cout<<"\nage = "; cin>>s1[j].age; cout<<"\nsem = "; cin>>s1[j].sem; cout<<"\nbranch= "; cin>>s1[j].branch; break; }

82

File Structures

} if(j==i) { cout<<"\n Record with usn "<<usn<<" is not present"; getch(); return; } in.close(); fstream out1; out1.open("student.txt",ios::out); if(!out1) { cout<<"\nUnable to open file in output mode"; getch(); return; } for(j=0;j<i;j++) { out1<<s1[j].name<<'|'<<s1[j].usn<<'|'<<s1[j].age<<'|' <<s1[j].sem<<'|'<<s1[j].sem<<'|'<<s1[j].branch<<'\n'; } out1.close(); } void main() { fstream in; fstream out; int ch; out.open("student.txt",ios::out); if(!in) { cout<<"\n\nCannot open the file in output mode"; getch(); exit(0); } out.close(); for(;;) { clrscr(); cout<<"\n 1: write to file\n 2:display the file" <<"\n 3:modify the file\n 4:search\n 5:exit";

File Structures

83

cout<<"\n\n Enter the choice: "; cin>>ch; switch(ch) { case 1: writeRecord();break; case 2: displayFile();break; case 3: modify();break; case 4: search (); break; case 5: exit(0); default: cout<<"\nInvalid input....";break; } } } Output : 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = ajay usn = 1vk07is002 age = 20 sem = 6 branch = ise

1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = rahul usn = 1vk07cs045 age = 20 sem = 6 branch = cse

1:write to file 2:display the file 3:modify the file

84

File Structures

4:search 5.exit Enter the choice:2 Name Usn ajay 1vk07is002 rahul 1vk07cs045 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:4 Enter the record's usn you want to search = Record found rahul 1vk07cs045 20 6 cse 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:5 C:\TC|BIN>type student.txt ajay|1vk07is002|20|6|ise rahul|1vk07cs045|20|6|cse 4. Write a c++ program to write student objects with variable-length records using any suitable record structure and to read from this file a student record using RRN. 1vk07cs045

Age 20 20

Sem 6 6

Branch ise cse

#include<stdio.h> #include<stdlib.h> #include<iostream.h> #include<fstream.h> #include<conio.h> #include<string.h> #include<iomanip.h> class student {

File Structures

85

public: char name[15],usn[15],age[5],sem[5],branch[15], buffer[100]; }; void search() { char usn[15]; int i=0; student s1[100]; cout<<"\nEnter the usn to be searched: "; cin>>usn; fstream in; in.open("student.txt",ios::in); if(!in) { cout<<"\ncannot open the file in output mode"; getch(); exit(0); } i=0; printf("Name\tUsn\tAge\tSem\tBranch\n"); while(!in.eof()) { in.getline(s1[i].name,15,'|'); in.getline(s1[i].usn,15,'|'); in.getline(s1[i].age,5,'|'); in.getline(s1[i].sem,5,'|'); in.getline(s1[i].branch,15,'\n'); i++; } for(int j=0; j<i-1; j++) { if(strcmp(usn,s1[j].usn)==0) { printf("\n Record found"); printf("\n%s\t%s\t%s\t%s\t%s",s1[j].name,s1[j].usn, s1[j].age,s1[j].sem,s1[j].branch); return; } } cout<<"\nRecord not found"; return; } void writeRecord() { fstream app;

86

File Structures

student s; app.open("student.txt",ios::app); if(!app) { cout<<"cannot open the file in output mode"; getch(); exit(0); } cout<<"\nEnter the student name: "; cin>>s.name; cout<<"\nEnter the usn: "; cin>>s.usn; cout<<"\nEnter the age: "; cin>>s.age; cout<<"\nEnter the sem: "; cin>>s.sem; cout<<"\nEnter the branch: "; cin>>s.branch; strcpy(s.buffer,s.name); strcat(s.buffer,"|"); strcat(s.buffer,s.usn); strcat(s.buffer,"|"); strcat(s.buffer,s.age); strcat(s.buffer,"|"); strcat(s.buffer,s.sem); strcat(s.buffer,"|"); strcat(s.buffer,s.branch); strcat(s.buffer,"\n"); app<<s.buffer; app.close(); } void main() { clrscr(); int ch; fstream out; out.open("student.txt",ios::out); if(!out) { cout<<"\nCannot open the file in output mode"; getch(); exit(0); } out.close(); for(;;) { cout<<"\n1:Insert\n2:Search\n3:exit" <<"\nEnter the choice = "; cin>>ch; switch(ch) { case 1: writeRecord();break; case 2: search();break; case 3: exit(0); default: cout<<"\nInvalid option"; }

File Structures

87

} } Output : 1:Insert 2.Search 3.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = ajay usn = 1vk07is002 age = 20 sem = 6 branch = ise

1:Insert 2.Search 3.exit

Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = rahul usn = 1vk07cs045 age = 20 sem = 6 branch = cse

1:Insert 2.Search 3.exit Enter the choice:2 Enter the usn to be searched:1vk07is007 Record not found 1:Insert 2.Search 3.exit

Enter the choice:2 Enter the usn to be searched:1vk07cs045 Record found

88
5.

File Structures

Write a C++ program to implement simple index on primary key for a file of student objects. Implement add(),search(),delete() using the index.

#include<iostream.h> #include<string.h> #include<fstream.h> #include<stdlib.h> //Record specification class record { public: char age[5]; char usn[20],name[20],branch[5]; char sem[2]; }rec[20]; char st_no[5]; int no; void retrieve_details() { fstream file2; char name[20],usn[20],branch[5]; char ind[5],age[5],sem[5]; file2.open("record.txt",ios::in); for(int i=0;i<no;i++) //Unpacking record data { file2.getline(ind,5,'|'); file2.getline(usn,20,'|'); file2.getline(name,20,'|'); file2.getline(age,5,'|'); file2.getline(sem,5,'|'); file2.getline(branch,5,'\n'); if(strcmp(ind,st_no)==0) //Required record found - print details { cout<<"\n\n"<<"Student details are: "; cout<<"\n\nUSN: "<<usn<<"\nName: "<<name<<"\nAge: "<<age<<"\nSem: "<<sem<<"\nBranch: "<<branch<<"\n"; } } file2.close(); } void delete_record(char usno[]) {

File Structures

89

int i; fstream file1, file2; char age[5],sem[5],branch[5],usn[20],name[20],ind[5]; file2.open("record.txt",ios::in); for(i=0;i<no;i++) //Unpack records { file2.getline(ind,5,'|'); file2.getline(usn,20,'|'); file2.getline(name,20,'|'); file2.getline(age,5,'|'); file2.getline(sem,5,'|'); file2.getline(branch,5,'\n'); strcpy(rec[i].usn,usn); strcpy(rec[i].name,name); strcpy(rec[i].age,age); strcpy(rec[i].sem,sem); strcpy(rec[i].branch,branch); } int flag=-1; for(i=0;i<no;i++) //Check for the record's existence { if(strcmp(rec[i].usn,usno)==0) flag=i; } if(flag==-1) //Record not found { cout<<"Error !\n"; return; } if(flag==(no-1)) //Delete found record { no--; cout<<"Deleted !\n"; return; } for(i=flag;i<no;i++) { rec[i]=rec[i+1]; } no--; cout<<"\nDeleted !\n"; file2.close(); file1.open("index.txt",ios::out); //Open index and record files file2.open("record.txt",ios::out); //After deletion

90

File Structures

for(i=0;i<no;i++) //Pack index n record data onto files { file1<<rec[i].usn<<"|"<<i<<"\n"; file2<<i<<"|"<<rec[i].usn<<"|"<<rec[i].name<<"|" <<rec[i].age<<"|"<<rec[i].sem<<"|"<<rec[i].branch<<"\n"; } file1.close(); file2.close(); return; } int main() { fstream file1,file2; int ch; char rt_usn[20],st_usn[20]; char ind[2],name[20],age[2],sem[5],branch[5]; int i,flag,flag1; file1.open("index.txt",ios::out); file2.open("record.txt",ios::out); if(!file1 || !file2) { cout<<"File creation Error! \n"; exit(0); } for(;;) { cout<<"\n1: Add Record" <<"\n2: Search Record" <<"\n3: Delete Record" <<"\n4: Display Record" <<"\n5: Exit" <<"\n\n Enter u'r choice :"; cin>>ch; switch(ch) { case 1: cout<<"Enter the no. of students : "; cin>>no; cout<<"Enter the details:\n"; for(i=0;i<no;i++) //Pack data onto the index and record files { //USN is the indexed data cout<<"\nName: "; cin>>rec[i].name; cout<<"Age: "; cin>>rec[i].age; cout<<"USN: "; cin>>rec[i].usn; cout<<"Sem: "; cin>>rec[i].sem; cout<<"Branch: "; cin>>rec[i].branch;

File Structures

91

file1<<rec[i].usn<<"|"<<i<<"\n"; file2<<i<<"|"<<rec[i].usn<<"|"<<rec[i].name<<"|" <<rec[i].age<<"|"<<rec[i].sem<<"|"<<rec[i].branch<<"\n"; } file1.close(); file2.close(); break; case 2: cout<<"Enter USN whose record is to be displayed: "; cin>>st_usn; file1.open("index.txt",ios::in); if(!file1) { cout<<"\nError !\n"; exit(0); } flag1=0; for(i=0;i<no;i++) { file1.getline(rt_usn,20,'|'); //Unpack index file and file1.getline(st_no,4,'\n'); //look for a match in the USN if(strcmp(st_usn,rt_usn)==0) { retrieve_details(); //Retrieve details if index found flag1=1; } } if(!flag1) cout<<"Record search failed!\n"; file1.close(); break; case 3: cout<<"Enter USN whose record is to be deleted: "; cin>>st_usn; file1.open("index.txt", ios::in); if(!file1) { cout<<"Error! \n"; exit(0); } flag=0; for(i=0;i<no;i++) { file1.getline(rt_usn,20,'|'); //Search index file and file1.getline(st_no,4,'\n'); //call del if index found if(strcmp(st_usn, rt_usn)==0) { delete_record(rt_usn);

92

File Structures

flag=1; } } if(!flag) cout<<"Deletion Failed\n"; file1.close(); break; case 4: for(i=0;i<no;i++) { cout<<"\n\n USN: "<<rec[i].usn <<"\n Name: "<<rec[i].name <<"\n Age: "<<rec[i].age <<"\n Sem: "<<rec[i].sem <<"\n Branch: "<<rec[i].branch; } break; case 5:exit(0); default: cout<<"Invalid choice"; exit(0); break; } } } Output : 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit

Enter u'r choice : 1 Enter the no. of students :2 Enter the details: Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise Name: rahul Age: 20 USN: 1vk07cs045

File Structures

93

Sem: 6 Branch: cse 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit

Enter u'r choice : 4 Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise Name: rahul Age: 20 USN: 1vk07cs045 Sem: 6 Branch: cse 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit

Enter u'r choice :3 Enter USN whose record is to be deleted:1vk07cs045 Deleted ! 1: Add Record 2: Search Record 3: Delete Record 4: Display Record 5: Exit Enter u'r choice :4 Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise

94
6.

File Structures

Write a C++ program to implement index on secondary key, the name, for a file of student objects. Implement add(),search(),delete() using the secondary index.

#include<iostream.h> #include<string.h> #include<fstream.h> #include<stdlib.h> //using namespace std; class record { public: char age[5]; char usn[20],name[20],branch[5]; char sem[2]; }rec[20],found[20]; char st_no[5],rt_name[20]; int no; void sort_records() { int i,j; record temp; for(i=0;i<no-1;i++) for(j=0;j<no-i-1;j++) if(strcmp(rec[j].name, rec[j+1].name) > 0) { temp=rec[j]; rec[j]=rec[j+1]; rec[j+1]=temp; } } void create_indexfile() { fstream index,index2; int i; index.open("secindex.txt",ios::out); index2.open("record.txt",ios::out); for(i=0;i<no;i++) { index<<rec[i].name<<"|" <<rec[i].usn<<"|"<<i<<"\n"; index2<<i<<"|"<<rec[i].usn<<"|"<<rec[i].name<<"|"<<rec[i].age<<"|" <<rec[i].sem<<"|"<<rec[i].branch<<"\n";

File Structures

95

} } void retrieve_record(char* index) { fstream file; int i; char ind[2],usn[20],name[20],age[3],sem[3],branch[10]; file.open("record.txt",ios::in); for(i=0;i<no;i++) { file.getline(ind,4,'|'); file.getline(usn,20,'|'); file.getline(name,20,'|'); file.getline(age,4,'|'); file.getline(sem,4,'|'); file.getline(branch,5,'\n'); if(strcmp(index,ind) == 0) cout<<"\nUSN: "<<usn <<"\nName: "<<name <<"\nAge: "<<age <<"\nSem: "<<sem <<"\nBranch: "<<branch; } file.close(); return; } void retrieve_details() { int k=0,i; char name[20],usn[20],ind[2]; char chusn[20]; char index[20][20]; fstream file; file.open("secindex.txt",ios::in); for(i=0;i<no;i++) { file.getline(name,20,'|'); file.getline(usn,20,'|'); file.getline(ind,4,'\n'); if(strcmp(name,rt_name) == 0) { strcpy(found[k].name,name); strcpy(found[k].usn,usn); strcpy(index[k],ind);

96

File Structures

k++; } } file.close(); if(k==1) { retrieve_record(index[0]); return; } else { cout<<"Please choose the candidate's USN: \n"; for(i=0;i<k;i++) cout<<"Name: "<<found[i].name<<" USN: "<<found[i].usn<<endl; } cin>>chusn; for(i=0;i<k;i++) { if(strcmp(chusn,found[i].usn) == 0) { retrieve_record(index[i]); return; } } cout<<"Invalid Entry! \n"; return; } void delete_record(char indx[]) { int i; fstream file1,file2; char age[5],sem[5],branch[5],usn[20],name[20],ind[5]; char index[20][20]; file2.open("record.txt",ios::in); for(i=0;i<no;i++) { file2.getline(ind,4,'|'); file2.getline(usn,20,'|'); file2.getline(name,20,'|'); file2.getline(age,5,'|'); file2.getline(sem,5,'|'); file2.getline(branch,8,'\n'); strcpy(index[i],ind); strcpy(rec[i].usn,usn); strcpy(rec[i].name,name);

File Structures

97

strcpy(rec[i].age,age); strcpy(rec[i].sem,sem); strcpy(rec[i].branch,branch); } int flag=-1; for(i=0;i<no;i++) { if(strcmp(index[i],indx) == 0) flag=i; } if(flag==-1) { cout<<"Error!\n"; return; } if(flag==(no-1)) { no--; cout<<"Deleted!\n"; return; } for(i=flag;i<no;i++) { rec[i]=rec[i+1]; } no--; cout<<"Deleted!\n"; file2.close(); file1.open("secindex.txt",ios::out); file2.open("record.txt",ios::out); for(i=0;i<no;i++) { file1<<rec[i].name<<"|"<<rec[i].usn<<"|"<<i<<"\n"; file2<<i<<"|"<<rec[i].usn<<"|"<<rec[i].name<<"|" <<rec[i].age<<"|"<<rec[i].sem<<"|"<<rec[i].branch<<"\n"; } file1.close(); file2.close(); return; } void delete_index(char* nam) { fstream file;

98

File Structures

int i; int k=0; char name[20],usn[20],ind[5],index[20][20],chusn[20]; file.open("secindex.txt",ios::in); for(i=0;i<no;i++) { file.getline(name,20,'|'); file.getline(usn,20,'|'); file.getline(ind,4,'\n'); if(strcmp(nam,name)==0) { strcpy(found[k].name,name); strcpy(found[k].usn,usn); strcpy(index[k],ind); k++; } } file.close(); if(k==1) { delete_record(index[0]); return; } else { cout<<"Please choose the candidate's USN: \n"; for(i=0;i<k;i++) { cout<<"Name: "<<found[i].name<<" USN: "<<found[i].usn<<endl; } } cin>>chusn; for(i=0;i<k;i++) { if(strcmp(chusn,found[i].usn)==0) { delete_record(index[i]); return; } } cout<<"Invalid Entry!\n"; return; } int main() {

File Structures

99

fstream file1,file2; int ch; char rt_usn[20],st_name[20],st_usn[20]; char ind[2],name[20],age[2],sem[5],branch[5]; int i,flag,flag1; file1.open("index.txt",ios::out); file2.open("record.txt",ios::out); if(!file1 || !file2) { cout<<"File creation Error!\n"; exit(0); } for(;;) { cout<<"\nl:Add Record\n2:Search Record" <<"\n3:Delete Record\n4:Display Record\n5:Exit" <<"\n\nEnter u'r choice :"; cin>>ch; switch(ch) { case 1: cout<<"Enter the no. of students : "; cin>>no; cout<<"Enter the details :\n"; for(i=0;i<no;i++) { cout<<"\nName : "; cin>>rec[i].name; cout<<"Age : "; cin>>rec[i].age; cout<<"USN : "; cin>>rec[i].usn; cout<<"Sem : "; cin>>rec[i].sem; cout<<"Branch : "; cin>>rec[i].branch; } sort_records(); create_indexfile(); file1.close (); file2.close(); break; case 2: cout<<"Enter name of the student whose record is to be displayed\n"; cin>>st_name; file1.open("secindex.txt",ios::in); if(!file1) { cout<<"Error !\n"; exit(0); } flag1=0;

100 File Structures


for(i=0;i<no;i++) { file1.getline(rt_name,20,'|'); file1.getline(rt_usn,20,'|'); file1.getline(st_no,4,'\n'); if(strcmp(st_name,rt_name)==0) { retrieve_details(); flag1=1; goto one; } } one: if(!flag1) cout<<"Record search failed !\n"; file1.close(); break; case 3: cout<<"Enter name of student whose record is to be deleted\n"; cin>>st_name; file1.open("secindex.txt",ios::in); if(!file1) { cout<<"Error !\n"; exit(0); } flag=0; for(i=0;i<no;i++) { file1.getline(rt_name,20,'|'); file1.getline(rt_usn,20,'|'); file1.getline(ind,4,'\n'); if(strcmp(st_name,rt_name) == 0) { delete_index(rt_name); flag=1; } } if(!flag) cout<<"Deletion failed !\n"; file1.close(); break; case 4: for(i=0;i<no;i++)

File Structures

101

{ cout<<"\n\nUSN : "<<rec[i].usn <<"\nName: "<<rec[i].name <<"\nAge : "<<rec[i].age <<"\nSem : "<<rec[i].sem <<"\nBranch : "<<rec[i].branch<<"\n"; } break; case 5:exit(0); default: cout<<"Invalid option !\n"; exit(0); break; } } } Output : 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit

Enter u'r choice : 1 Enter the no. of students :2 Enter the details: Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise Name: rahul Age: 20 USN: 1vk07cs045 Sem: 6 Branch: cse 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit

102 File Structures


Enter u'r choice : 4 Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise Name: rahul Age: 20 USN: 1vk07cs045 Sem: 6 Branch: cse 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit

Enter u'r choice :3 Enter USN whose record is to be deleted:1vk07cs045 Deleted ! 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit

Enter u'r choice :4 Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise 7. Write a C++ program to read two lists of names and then match the names in the two lists using Consequential Match based on a single loop. Output the names common to both the lists.

#include<stdio.h> #include<stdlib.h> #include<string.h>

File Structures

103

#include<conio.h> #include<fstream.h> #include<iostream.h> void writeLists() { fstream out1,out2; int i,m,n; char name[20]; out1.open("file1.txt",ios::out); out2.open("file2.txt",ios::out); if( (!out1) || (!out2) ) { cout<<"Unable to open one of the list files"; getch(); exit(0); } cout<<"Enter no. of names you want to enter in file1 :"; cin>>m; cout<<"\nEnter the names in ascending order\n"; for(i=0;i<m;i++) { cin>>name; out1<<name; out1<<'\n'; } cout<<"Enter no. of names you want to enter in file2 :"; cin>>n; cout<<"\nEnter the names in ascending order \n"; for(i=0;i<n;i++) { cin>>name; out2<<name; out2<<'\n'; } out1.close(); out2.close(); } void main() { char list1[100][20], list2[100][20]; int i,j,m,n; clrscr(); fstream out1,out2,out3; writeLists();

104 File Structures


out1.open("file1.txt",ios::in); out2.open("file2.txt",ios::in); out3.open("file3.txt",ios::out); if( (!out3) || (!out1) || (!out2) ) { printf("Unable to open one of the file"); getch(); exit(0); } clrscr(); m=0; n=0; while(!out1.eof()) { out1.getline(list1[m],20,'\n'); cout<<list1[m]; m++; } while(!out2.eof()) { out2.getline(list2[n],20,'\n'); cout<<list2[n]; n++; } m--; n--; i=0; j=0; cout<<"\nElements common to both files are: \n "; while(i<m && j<n) { if( strcmp(list1[i],list2[j]) == 0 ) { out3<<list1[i]; cout<<list1[i]<<"\n"; out3<<'\n'; i++; j++; } else if( strcmp(list1[i],list2[j]) < 0 ) i++; else j++; }

File Structures

105

getch(); } Output : Enter no. of names you want to enter in file1 : 3 Enter the names in ascending order cse ise tc Enter no. of names you want to enter in file1 : 2 Enter the names in ascending order ec ise cseisetcecise Elements common to both files are: ise 8. Write a C++ program to read k Lists of names and merge them using kway merge algorithm with k = 8.

#include<iostream.h> #include<fstream.h> #include<string.h> #include<conio.h> // Record specification class record { public: char name[20]; char usn[20]; }rec[20]; int no; fstream file[8]; //The first 8 files char fname[8][8] = {"l.txt","2.txt","3.txt","4.txt","5.txt", "6.txt","7.txt","8.txt"};

106 File Structures


void merge_file(char* file1, char* file2, char* filename) { record recrd[20]; int k; k=0; fstream f1,f2; f1.open(file1,ios::in); //open the first file f2.open(file2,ios::in); //open the second file while(!f1.eof()) //Unpack and retrieve first file { f1.getline(recrd[k].name,20,'|'); f1.getline(recrd[k++].usn,20,'\n'); } while(!f2.eof()) //Unpack and retrieve second file { f2.getline(recrd[k].name,20,'|'); f2.getline(recrd [k++].usn, 20,'\n'); } record temp; int t,y; for(t=0;t<k-2;t++) //Sort the retrieved records for(y=0;y<k-t-2;y++) if(strcmp(recrd[y].name,recrd[y+1].name)>0) { temp=recrd[y]; recrd[y]=recrd[y+1]; recrd[y+1]=temp; } fstream temp1; temp1.open(filename,ios::out); //Open the file to be packed into for(t=1;t<k-1;t++) //Pack the sorted records onto the file temp1<<recrd[t].name<<"|"<<recrd[t].usn<<"\n"; f1.close(); f2.close(); temp1.close(); return; } void kwaymerge() { char filename[7][20]={"ll.txt","22.txt","33.txt","44.txt"," lll.txtw","222.txt","llll.txr"}; int i; int k; k=0; for(i=0;i<8;i+=2) //Merge and sort the 8 original files onto { //the four files indicated {ll.txt,22.txt....} merge_file(fname[i],fname[i+1],filename[k++]);

File Structures

107

} k=4; for(i=0;i<4;i+=2) //Merge and sort the four files onto lll.txt and 222.txt { merge_file(filename[i],filename[i+1],filename[k++]); } //Merge and sort the two files onto the llll.txt file merge_file(filename[4],filename[5],filename[6]); return; } void main() { int i; clrscr(); cout<<"Enter the no. of records : "; cin>>no; cout<<"\nEnter the details : \n"; for(i=0;i<8;i++) //Create 8 files to store the split data file[i].open(fname[i],ios::out); for(i=0;i<no;i++) //Split and pack data onto the files { cout<<"Name :"; cin>>rec[i].name; cout<<"USN : ";cin>>rec[i].usn; file[i%8]<<rec[i].name<<'|'<<rec[i].usn<<"\n"; } for(i=0;i<8;i++) file[i].close(); kwaymerge(); //Merge fstream result; result.open("lll.txt",ios::in); cout<<"\nSorted Records : \n"; char name[20],usn[20]; for(i=0;i<no;i++) //Unpack the sorted records and dispL { result.getline(name,20,'|'); result.getline(usn,20,'\n'); cout<<"\nName : "<<name<<"\nUSN : "<<usn<<"\n"; } getch(); } Output : Enter the no. of records :4

108 File Structures


Enter the details : Name :rahul USN :25 Name :laxmi USN :16 Name :ajay USN :2 Name :deepak USN :8 Sorted Records : Name :ajay USN :2 Name :deepak USN :8 Name :laxmi USN :16 Name :rahul USN :25 9. Write a C++ program to implement B-Tree for a given set of integers and its operations insert ( ) and search ( ). Display the tree.

#include<iostream.h> #include<stdio.h> #include<fstream.h> #include<stdlib.h> #include<string.h> class node { public: int a[4]; node * next[4]; node * parent; int size; node(); }; node :: node()

File Structures

109

{ for(int i = 0; i < 4; i++) next[i] = NULL; parent = NULL; size = 0; } class btree { node * root; public: node* findLeaf(int key,int &level); void updateKey(node *p,node *c,int newKey); void search(int key); void insert(int key); void insertIntoNode(node *n,int key,node *address); void promote(node *n,int key,node *address); node* split(node *n); void traverse(node *ptr); btree(); }; void btree :: traverse(node *ptr) { if(ptr == NULL) return; for(int i = 0; i < ptr->size; i++) cout<<ptr->a[i]<<" "; cout<<endl; for(i = 0; i < ptr->size;i++) traverse(ptr->next[i]); } btree :: btree() { root = NULL; } node* btree :: findLeaf(int key,int &level) { node *ptr = root; node *prevptr = NULL; level = 0; int i; while(ptr) { i = 0; level++; while(i < ptr -> size-1 && key > ptr -> a[i]) i++;

110 File Structures


prevptr = ptr; ptr = ptr -> next[i]; } return prevptr; } node* btree :: split(node *n) { int midpoint = (n -> size+1)/2; int newsize = n->size - midpoint; node *newptr = new node; node *child; newptr->parent = n -> parent; int i; for(i = 0; i < midpoint; i++) { newptr->a[i] = n->a[i]; newptr ->next[i] = n->next[i]; n->a[i] = n->a[i+midpoint]; n->next[i] = n->next[i+midpoint]; } n->size = midpoint; newptr -> size = newsize; for( i = 0; i < n->size; i++) { child = n->next[i]; if(child!= NULL) child -> parent = n; } for( i = 0; i < newptr -> size; i++) { child = newptr -> next[i]; if(child!= NULL) child -> parent = newptr; } return newptr; } void btree :: updateKey(node *parent,node *child,int newkey) { if( parent == NULL) return; if(parent->size == 0) return; int oldkey = child->a[child->size-2]; for(int i = 0; i < parent->size;i++) if(parent->a[i] == oldkey) {

File Structures

111

parent->a[i] = newkey; parent->next[i] = child; } } void btree :: insertIntoNode(node *n,int key,node *address) { int i; if( n == NULL) return; for(i = 0; i < n->size; i++) if(n->a[i] == key) return; i = n->size-1; while(i >= 0 && n -> a[i] > key) { n->a[i+1] = n->a[i]; n->next[i+1] = n->next[i]; i--; } i++; n->a[i] = key; n->next[i] = address; n->size++; if( i == n->size-1) updateKey(n->parent,n,key); } void btree :: promote(node *n,int key,node *address) { if( n == NULL) return; if(n -> size < 4) { insertIntoNode(n,key,address); return; } if( n == root) { root = new node; n->parent = root; } node *newptr = split(n); node *t; if(key < n->a[0]) t = newptr; else t = n;

112 File Structures


insertIntoNode(t,key,address); promote(n->parent,n->a[n->size-1],n); promote(newptr->parent,newptr->a[newptr->size-1],newptr); }

void btree :: insert(int key) { if( root == NULL) { root = new node; root->a[root->size] = key; root->size++; return; } int level; node *leaf = findLeaf(key,level); int i; for(i = 0; i < leaf->size; i++) if(leaf -> a[i] == key) { cout<<"The Key to be inserted already exists"<<endl; return; } promote(leaf,key,NULL); cout<<"---------------\n"; traverse(root); cout<<"----------------\n"; } void btree :: search(int key) { if(root == NULL) { cout<<"The tree Does not exist"<<endl; return; } int level; node *leaf = findLeaf(key,level); int flag = 0; for(int i = 0; i < leaf ->size; i++) if(leaf->a[i] == key) { flag = 1; cout<<"The Key "<<key<<" Exists in the B-Tree at the level"<<level<<endl; }

File Structures

113

if(!flag) cout<<"The Key Searched for was not found"<<endl; } int main() { btree b; int choice = 1,key; while(choice <=2) { cout<<"1.Insert a Key\n"; cout<<"2.Search a key\n"; cout<<"3.Exit\n"; cout<<\n\n Enter ur choice :; cin>>choice; switch(choice) { case 1: cout<<"Enter The Key to be inserted in B-Tree\n"; cin>>key; b.insert(key); break; case 2: cout<<"Enter The key to be searched\n"; cin>>key; b.search(key); break; } } return 0; } Output : 1.Insert a Key 2.Search a key 3.Exit Enter ur choice :1 Enter The Key to be inserted in B-Tree 100 1.Insert a Key 2.Search a key 3.Exit Enter ur choice :1

114 File Structures


Enter The Key to be inserted in B-Tree 50 ----------50 100 ----------1.Insert a Key 2.Search a key 3.Exit Enter ur choice :1 Enter The Key to be inserted in B-Tree 75 ------------50 75 100 ------------1.Insert a Key 2.Search a key 3.Exit Enter ur choice :1 Enter The Key to be inserted in B-Tree 200 --------------50 75 100 200 --------------1.Insert a Key 2.Search a key 3.Exit Enter ur choice :2 Enter The key to be searched 100 Key 100 exists in B-tree at level 1 10. Write a C++ program to implement B+ tree for a given set of integers and its operations insert ( ), and search ( ). Display the tree. #include<iostream.h> #include<stdio.h> #include<fstream.h>

File Structures

115

#include<stdlib.h> #include<string.h> class node { public: int a[4]; node * next[4]; node * parent; int size; node(); }; class linkleaf { public: node * data; linkleaf *next; linkleaf(); }; linkleaf :: linkleaf() { next = NULL; } node :: node() { for(int i = 0; i < 4; i++) next[i] = NULL; parent = NULL; size = 0; } class btree { node * root; linkleaf *head; int flag; public: node* findLeaf(int key,int &level); void updateKey(node *p,node *c,int newKey); void search(int key); void insert(int key); void insertIntoNode(node *n,int key,node *address); void promote(node *n,int key,node *address); node* split(node *n); void traverse(node *ptr);

116 File Structures


void connectLeaf(node *n,node *newptr); void traverseleaf(); btree(); }; void btree :: traverseleaf() { linkleaf * ptr = head; int i; while(ptr) { for(i = 0; i < ptr -> data -> size; i++) cout<<ptr -> data -> a[i]<<" "; cout<<endl; ptr = ptr ->next; } } void btree :: connectLeaf(node *n,node *newptr) { linkleaf *ptr = head,*prevptr = NULL,*p; while(ptr) { if(ptr-> data == n) break; prevptr = ptr; ptr = ptr ->next; } if( ptr == NULL) { cout<<"Unexpected Error!!"; exit(0); } if( ptr == head) { p = new linkleaf; p -> next = head; head = p; p->data = newptr; } else { p = new linkleaf; p-> next = ptr; prevptr -> next = p; p->data = newptr; } }

File Structures

117

void btree :: traverse(node *ptr) { if(ptr == NULL) return; for(int i = 0; i < ptr->size; i++) cout<<ptr->a[i]<<" "; cout<<endl; for(int j = 0; j < ptr->size; j++) traverse(ptr->next[j]); } btree :: btree() { root = NULL; head = NULL; } node* btree :: findLeaf(int key,int &level) { node *ptr = root; node *prevptr = NULL; level = 0; int i; while(ptr) { i = 0; level++; while(i < ptr -> size-1 && key > ptr -> a[i]) i++; prevptr = ptr; ptr = ptr -> next[i]; } return prevptr; } node* btree :: split(node *n) { int midpoint = (n -> size+1)/2; int newsize = n->size - midpoint; node *newptr = new node; node *child; newptr->parent = n -> parent; int i; for(i = 0; i < midpoint; i++) { newptr->a[i] = n->a[i]; newptr ->next[i] = n->next[i]; n->a[i] = n->a[i+midpoint];

118 File Structures


n->next[i] = n->next[i+midpoint]; } n->size = midpoint; newptr -> size = newsize; for( i = 0; i < n->size; i++) { child = n->next[i]; if(child!= NULL) child -> parent = n; } for( i = 0; i < newptr -> size; i++) { child = newptr -> next[i]; if(child!= NULL) child -> parent = newptr; } return newptr; } void btree :: updateKey(node *parent,node *child,int newkey) { if( parent == NULL) return; if(parent->size == 0) return; int oldkey = child->a[child->size-2]; for(int i = 0; i < parent->size;i++) if(parent->a[i] == oldkey) { parent->a[i] = newkey; parent->next[i] = child; } } void btree :: insertIntoNode(node *n,int key,node *address) { int i; if( n == NULL) return; for(i = 0; i < n->size; i++) if(n->a[i] == key) return; i = n->size-1; while(i >= 0 && n -> a[i] > key) { n->a[i+1] = n->a[i]; n->next[i+1] = n->next[i];

File Structures

119

i--; } i++; n->a[i] = key; n->next[i] = address; n->size++; if( i == n->size-1) updateKey(n->parent,n,key); } void btree :: promote(node *n,int key,node *address) { if( n == NULL) return; if(n -> size < 4) { insertIntoNode(n,key,address); return; } if( n == root) { root = new node; n->parent = root; } node *newptr = split(n); node *t; if(key < n->a[0]) t = newptr; else t = n; insertIntoNode(t,key,address); if(!flag) { connectLeaf(n,newptr);flag = 1;} promote(n->parent,n->a[n->size-1],n); promote(newptr->parent,newptr->a[newptr->size-1],newptr); } void btree :: insert(int key) { flag = 0; if( root == NULL) { root = new node; root->a[root->size] = key; root->size++; head = new linkleaf;

120 File Structures


head -> data = root; return; } int level; node *leaf = findLeaf(key,level); int i; for(i = 0; i < leaf->size; i++) if(leaf -> a[i] == key) { cout<<"The Key to be inserted already exists"<<endl; return; } promote(leaf,key,NULL); cout<<"---------------\n"; traverse(root); cout<<"----------------\n"; } void btree :: search(int key) { if(root == NULL) { cout<<"The tree Does not exist"<<endl; return; } int level; node *leaf = findLeaf(key,level); int flag = 0; for(int i = 0; i < leaf ->size; i++) if(leaf->a[i] == key) { flag = 1; cout<<"The Key "<<key<<" Exists in the B-Tree level"<<level<<endl; } if(!flag) cout<<"The Key Searched for was not found"<<endl; } int main() { btree b; int choice = 1,key; while(choice <=3) { cout<<"1.Insert a Key\n"; cout<<"2.Search a key\n";

at

the

File Structures

121

cout<<"3.Traverse Leaf\n"; cout<<"4.Exit\n"; cout<<\n enter ur choice :; cin>>choice; switch(choice) { case 1: cout<<"Enter The Key to be inserted in B-Tree\n"; cin>>key; b.insert(key); break; case 2: cout<<"Enter The key to be searched\n"; cin>>key; b.search(key); break; case 3: b.traverseleaf(); break; } } return 0; } Output : 1.Insert a Key 2.Search a key 3.Traverse Leaf 4.Exit enter ur choice : 1 Enter The Key to be inserted in B-Tree 100 1.Insert a Key 2.Search a key 3.Traverse Leaf 4.Exit enter ur choice : 1 Enter The Key to be inserted in B-Tree 50 -------50 100 --------

122 File Structures


1.Insert a Key 2.Search a key 3.Traverse Leaf 4.Exit enter ur choice : 1 Enter The Key to be inserted in B-Tree 200 ---------50 100 200 ---------1.Insert a Key 2.Search a key 3.Traverse Leaf 4.Exit enter ur choice : 1 Enter The Key to be inserted in B-Tree 75 --------------50 75 100 200 --------------1.Insert a Key 2.Search a key 3.Traverse Leaf 4.Exit enter ur choice : 2 Enter The key to be searched 300 The Key Searched for was not found 11. Write a C++ program to store and retrieve student data from file using hashing. Use any collision resolution technique #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> #include<fstream.h>

File Structures

123

#include<iostream.h> //Record specification class node { public: char name[15],usn[15]; node *link; }; node *h[29]; keys - 29 //Array of record pointers equal to size of hash

void insert() { char name[15], usn[15], buffer[50]; fstream out; out.open("student.txt",ios::app); //opening student.txt in append mode if(!out) { cout<<"\nUnable to open the file in append mode"; getch(); return; } cout<<"\nEnter the name = "; cin>>name; cout<<"\nEnter the usn = "; cin>>usn; strcpy(buffer,name); //Packing the record onto the file using '|' as a delimiter strcat(buffer,"|"); strcat(buffer,usn); strcat(buffer,"\n"); // \n delimiter for the record out<<buffer; // appending the packed record onto the file out.close(); } //Insert record into the hash table void hash_insert(char name1[], char usn1[], int hash_key) { node *p,*prev,*curr; p = new node; //dynamically allocate space using 'new' strcpy(p->name,name1); strcpy(p->usn,usn1); p->link=NULL;

124 File Structures


prev=NULL; curr=h[hash_key]; if(curr==NULL) //getting hash pointer location Case: No collision { h[hash_key]=p; return; } while(curr!=NULL) // Case : On collision - Insert at rear end { prev=curr; curr=curr->link; } prev->link=p; } void retrive() { fstream in; char name[15],usn[15]; int j,count; node *curr; in.open("student.txt",ios::in); // open record file in input mode if(!in) { cout<<"\n Unable to open the file in input mode"; getch(); exit(0); } while(!in.eof()) { in.getline(name,15,'|'); //unpacking the record in.getline(usn,15,'\n'); count=0; for(j=0; j<strlen(usn); j++) { count=count+usn[j]; } count=count%29; //Hash Key = ASCII count% 29 hash_insert(name,usn,count); } cout<<"\n Enter the usn = "; cin>>usn; count=0; for(j=0; j<strlen(usn); j++) // Calculating Hash Key count=count+usn[j];

File Structures

125

count=count%29; curr=h[count]; if(curr == NULL) { cout<<"\nRecord not found"; getch(); return; } do { if(strcmp(curr->usn,usn)==0) //When the record is found, retrieve { cout<<"\nRecord found : "<<curr->usn<<" "<<curr->name; getch(); return; } else { curr=curr->link; } }while(curr!=NULL); //Search till end of list if(curr==NULL) //End of list reached with no record found { cout<<"\nRecord not found"; getch(); return; } } void main() { int choice; clrscr(); fstream out; out.open("student.txt",ios::out); if(!out) { cout<<"\nUnable to open the file in out mode"; getch(); exit(0); } for(;;) { cout<<"\n1:insert\n2: retrive\n3:exit\nEnter the choice - ";

126 File Structures


cin>>choice; switch(choice) { case 1: insert(); break; case 2: retrive(); break; case 3: exit(0); default: cout<<"\nInvalid option"; } } } Output : 1:insert 2:retrive 3:exit Enter the choice 1 Enter the name ajay Enter the usn - 10 1:insert 2:retrive 3:exit Enter the choice 1 Enter the name rahul Enter the usn - 20 1:insert 2:retrive 3:exit Enter the choice 1 Enter the name deepak Enter the usn - 30 1:insert 2:retrive 3:exit Enter the choice 2

File Structures

127

Enter the usn =

20

Record found : rahul 20 12. Write a C++ program to reclaim the free space resulting from the deletion of records using linked lists. #include<stdio.h> #include<conio.h> #include<stdlib.h> #include<string.h> #include<iostream.h> #include<fstream.h> #include<new.h> class node { public: char name[20]; char usn[20]; node *link; }; node *first=NULL; void writeFile() { node *p; char buffer[100]; fstream out; out.open("student.txt", ios::out); if(!out) { cout<<"\n Unable to open the file student.txt in out mode"; getch(); exit(0); } p=first; while(p!=NULL) { strcpy(buffer,p->name); strcat(buffer,"|"); strcat(buffer,p->usn); strcat(buffer,"\n"); out<<buffer; p=p->link; } }

128 File Structures


void display() { node *p; if(first==NULL) { cout<<"\nList is empty"; return; } p=first; while(p!=NULL) { cout<<"|"<<p->name<<" "<<p->usn<<"|"<<"->"; p=p->link; } } void Insert() //Insert the record at the rear end { char name[20],usn[15]; node *p,*q; cout<<"\n Enter name = "; cin>>name; cout<<"\nEnter usn = "; cin>>usn; p=new node; strcpy(p->name,name); strcpy(p->usn,usn); p->link=NULL; if(first==NULL) { first=p; writeFile(); display(); //display the record on the screen return; } for(q=first; q->link!=NULL; q=q->link) { ; } q->link=p; writeFile(); //writing the record to the file display(); //display the records to the screen. } void Delete() { char usn[15]; node *curr,*prev,*del; if(first==NULL)

File Structures

129

{ printf("\nThe list is empty. Deletion is not possible"); return; } cout<<"\nEnter the usn to be deleted = "; cin>>usn; if(strcmp(first->usn,usn)==0) { cout<<"\n Record deleted"; del = first; delete del; first=first->link; writeFile(); return; } prev=NULL; curr=first; while( ( strcmp(curr->usn,usn) != 0 ) && curr!=NULL) { prev=curr; curr=curr->link; } if(curr == NULL) { cout<<"\nThe student with usn "<<usn<<" is not present"; return; } prev->link = curr->link; writeFile(); display(); //display the records to the screen } void main() { int ch; clrscr(); for(;;) { cout<<"\n 1-Insert_rear \n 2-Delete_id \n 3-Exit \n Enter choice :"; cin>>ch; switch(ch) { case 1: Insert(); break; case 2: Delete(); break; case 3: exit(0);

130 File Structures


default: cout<<"\n Invalid option"; break; } } } Output : 1-Insert_rear 2-Delete_id 3-Exit Enter choice : 1 Enter name : ajay Enter USN : 10 |ajay 10|-> 1-Insert_rear 2-Delete_id 3-Exit Enter choice : 1 Enter name : rahul Enter USN : 20 |ajay 10|rahul 20|-> 1-Insert_rear 2-Delete_id 3-Exit Enter choice : 1 Enter name : deepak Enter USN : 30 |ajay 10|rahul 20|Deepak 30|-> 1-Insert_rear 2-Delete_id 3-Exit Enter choice :2 Enter the usn to be deleted = 20 |ajay 10|Deepak 30|->

Computer Graphics and Visualization

131

COMPUTER GRAPHICS AND VISUALIZATION LABORATORY


PART A
IMPLEMENT THE FOLLOWING PROGRAMS IN C / C++
1. 2. 3. 4. 5. Program to recursively subdivides a tetrahedron to from 3D Sierpinski gasket. The number of recursive steps is to be specified by the user. Program to implement Liang-Barsky line clipping algorithm. Program to draw a color cube and spin it using OpenGL transformation matrices. Program to create a house like figure and rotate it about a given fixed point using OpenGL functions. Program to implement the Cohen-Sutherland line-clipping algorithm. Make provision to specify the input line, window for clipping and view port for displaying the clipped image. Program to create a cylinder and a parallelepiped by extruding a circle and quadrilateral respectively. Allow the user to specify the circle and the quadrilateral. Program, using OpenGL functions, to draw a simple shaded scene consisting of a tea pot on a table. Define suitably the position and properties of the light source along with the properties of the properties of the surfaces of the solid object used in the scene. Program to draw a color cube and allow the user to move the camera suitably to experiment with perspective viewing. Use OpenGL functions. Program to fill any given polygon using scan-line area filling algorithm. (Use appropriate data structures.)

6.

7.

8. 9.

10. Program to display a set of values { fij } as a rectangular mesh.

Procedure to run programs


Install GLUT 3.7 on your PC 1. 2. Find where the OpenGL32.dll is installed on your computer. It is generally at: C:\WINNT\SYSTEM32 or C:\WINDOWS\SYSTEM32 Copy glut32.dll to the above directory, you may need to have administrator's privilege

132 Computer Graphics and Visualization


3. Find the Visual Studio lib path: generally at: C:\Program Files\Microsoft Visual Studio\VC\lib or C:\Program Files\Microsoft Visual Studio .NET 2003\VC7\lib, or C:\Program Files\Microsoft Visual Studio 2005\VC8\lib, depending on your Visual Studio version. Copy glut32.lib to the above directory Find the Visual Studio include path: should be similar to 3 while \lib changes to \include Copy glut.h to the above directory.

4. 5. 6.

Introduction to opengl :
GLUT stands for OpenGL Utility Toolkit. Mark J. Kilgard, to enable the construction of OpenGL applications that are truly window system independent, conceived the GLUT library. Thanks to GLUT, we can write applications without having to learn about X windows or Microsoft's own window system. Kilgard implemented the version for X windows, and later Nate Robins ported it to Microsoft Windows. The main function will perform the required initializations and start the event processing loop. All the functions in GLUT have the prefix glut, and those which perform some kind of initialization have the prefix glutInit. The first thing you must do is call the function glutInit. void glutInit(int *argc, char **argv); Parameters : argc - A pointer to the unmodified argc variable from the main function. argv - A pointer to the unmodified argv variable from the main function. After initializing GLUT itself, we're going to define our window. First we establish the window's position, i.e. its top left corner. In order to do this we use the function glutInitWindowPosition. glutInitWindowPosition(int x, int y); Parameters : x - the number of pixels from the left of the screen. -1 is the default value, meaning it is up to the window manager to decide where the window will appear. If not using the default values then you should pick a positive value, preferably one that will fit in your screen. y - the number of pixels from the top of the screen. Note that these parameters are only a suggestion to the window manager. The window returned may be in a different position, although if you choose them wisely you'll usually get what you want. Next we'll choose the window size. In order to do this we use the function glutInitWindowSize. void glutInitWindowSize(int width, int height); Parameters : width - The width of the window height - the height of the window

Computer Graphics and Visualization

133

Again the values for width and height are only a suggestion, so avoid choosing negative values. Then you should define the display mode using the function glutInitDisplayMode. void glutInitDisplayMode(unsigned int mode) Parameters : mode - specifies the display mode The mode parameter is a Boolean combination (OR bit wise) of the possible predefined values in the GLUT library. You use mode to specify the color mode, and the number and type of buffers. The predefined constants to specify the color model are : GLUT_RGBA or GLUT_RGB - selects a RGBA window. This is the default color mode. GLUT_INDEX - selects a color index mode. The display mode also allows you to select either a single or double buffer window. The predefined constants for this are: GLUT_SINGLE - single buffer window GLUT_DOUBLE - double buffer window, required to have smooth animation. There is more, you can specify if you want a window with a particular set of buffers. The most common are : 1. GLUT_ACCUM - The accumulation buffer 2. GLUT_STENCIL - The stencil buffer 3. GLUT_DEPTH - The depth buffer So, suppose you want a RGB window, with single buffering, and a depth buffer. All you have to do is to OR all the respective constants in order to create the required display mode. ... glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT DEPTH); ... After all the above steps, the window can be created with glutCreateWindow. int glutCreateWindow(char *title); Parameters : title - sets the window title The return value of glutCreateWindow is the window identifier. So now here is a little bit of code to perform all the initializations : #include <GL/glut.h> void main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("3D Tech- GLUT Tutorial"); }

134 Computer Graphics and Visualization


Note the include statement at the beginning of the code. The required include file comes with the GLUT distribution. If you run this code, you'll obtain an empty black console window but no OpenGL window. Furthermore after a few seconds the window disappears. There are two things left to do before we are ready to render something. The first is to tell GLUT what is the function responsible for the rendering. Lets create an example function for the rendering. The function presented bellow will clear the color buffer and draw a triangle. void renderScene(void) { glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLES); glVertex3f(-0.5,-0.5,0.0); glVertex3f(0.5,0.0,0.0); glVertex3f(0.0,0.5,0.0); glEnd(); glFlush(); } The name of this function is up to you. However, now you must tell GLUT that it should use that function we just wrote for the rendering. This is called registering a callback. GLUT will call the function you supply whenever rendering is in order. For now lets tell GLUT that the function renderScene should be used whenever the window is reported by the window system to be damaged. GLUT has a function that takes as a parameter the name of the function to use when redrawing is needed. Note: the function you supply as a parameter is also called the first time the window is created. The syntax is as follows : void glutDisplayFunc(void (*func)(void)); Parameters : func - the name of the function to be called when the window needs to be redrawn. Note: it is illegal to pass NULL as the argument to this function. One last thing missing, that is telling GLUT that we're ready to get in the application event processing loop. GLUT provides a function that gets the application in a never ending loop, always waiting for the next event to process. The GLUT function is glutMainLoop, and the syntax is as follows: void glutMainLoop(void) The code so far is presented bellow. Note that we've added an include statement in order to start using standard OpenGL functions, like glClear, glBegin, glVertex3f, and glEnd. .If you try to run this code you'll get a console window, and a few instants after the OpenGL window with a white triangle, hopefully at the desired position and with the desired size.

Computer Graphics and Visualization

135

#include <GL/glut.h> void renderScene(void) { glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLES); glVertex3f(-0.5,-0.5,0.0); glVertex3f(0.5,0.0,0.0); glVertex3f(0.0,0.5,0.0); glEnd(); glFlush(); } void main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("3D Tech- GLUT Tutorial"); glutDisplayFunc(renderScene); glutMainLoop(); } GLUT provides a way to define which function should be called when the window is resized, i.e. to register a callback for recomputing the perspective. Furthermore, this function will also be called when the window is initially created so that even if you're initial window is not square things will look OK. GLUT achieves this using the function glutReshapeFunc. void glutReshapeFunc(void (*func)(int width, int height)); Parameters : func - The name of the function that will be responsible for setting the correct perspective when the window changes size. So the first thing that we must do is to go back to the main function we defined in the previous section and add a call to glutReshapeFunc. Lets call our own function to take care of window resizes changeSize. The code for the main function with the call to glutReshapeFunc added in is: void main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320);

136 Computer Graphics and Visualization


glutCreateWindow("3D Tech- GLUT Tutorial"); glutDisplayFunc(renderScene); // Here is our new entry in the main function glutReshapeFunc(changeSize); glutMainLoop(); } The next thing we need to do is to define the function that we'll take care of the perspective. As seen by the syntax of glutReshapeFunc, the changeSize function has two arguments, these are the new width and height, respectively, of the client area of the window, i.e. without the window decorations. void changeSize(int w, int h) { // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if(h == 0) h = 1; float ratio = 1.0* w / h; // Reset the coordinate system before modifying glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Set the viewport to be the entire window glViewport(0, 0, w, h); // Set the correct perspective. gluPerspective(45,ratio,1,1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0,0.0,5.0, 0.0,0.0,-1.0, 0.0f,1.0f,0.0f); } A few functions we're introduced in this piece of code so let's go into a bit of detail in here before we all get lost. The first step was to compute the ratio between the width and the height. Note that in order for this to be done correctly we must take care of the case when the height of a window is actually zero to prevent a division by zero. We then set the current matrix to be the projection matrix. This is the matrix that defines the viewing volume. We then load the identity matrix to initialize it. Afterwards we set the viewport to be the whole window with the function glViewport. You can try

Computer Graphics and Visualization

137

with different values to see what you come up with, the first two parameters are the top right corner, and the last two are the bottom left. Note that these coordinates are relative to the client area of the window, not the screen. If you do try with different values then don't forget that the ratio computed above should also use the new width and height values. The gluPerspective function is part of another library for OpenGL, the OpenGL Utility Library, or GLU. GLU is a standard component of the implementation of OpenGL. The gluPerspective function establishes the perspective parameters. The first one defines the field of view angle in the yz plane, the ratio defines the relation between the width and height of the viewport. The last two parameters define the near and far clipping planes. Anything closer than the near value, or further away than the far value will be clipped away from the scene. Beware with these settings or you may end up not seeing anything at all. Finally, setting the camera. First we set the GL_MODELVIEW as our current matrix. the modelview matrix is where we'll define both the camera settings and the modeling transformations. Before setting the camera it is always healthy to load the identity matrix. this avoids previous transformations to affect the camera settings. The gluLookAt function provides an easy and intuitive way to set the camera position and orientation. Basically it has three groups of parameters, each one is composed of 3 floating point values. The first three values indicate the camera position. The second set of values defines the point we're looking at. Actually it can be any point in our line of sight.The last group indicates the up vector, this is usually set to (0.0, 1.0, 0.0), meaning that the camera's is not tilted. If you want to tilt the camera just play with these values. For example, to see everything upside down try (0.0, -1.0, 0.0). OK, so far so good. We have an OpenGL window with a white triangle. Nothing very exciting, but hey, its a start. Now to complete this part of the GLUT tutorial lets have that triangle spinning. Lets go back to the main function and add some extra stuff. First lets tell GLUT that we want a double buffer. Double buffering allows for smooth animation by keeping the drawing in a back buffer and swapping the back with the front buffer (the visible one) when the rendering is complete. Using double buffering prevents flickering. ... glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); ... The second thing we must do is to tell GLUT that when the application is idle the render function should be called. This causes GLUT to keep calling our rendering function therefore enabling animation. GLUT provides a function, glutIdleFunc, that lets you register a callback function to be called when the application is idle. void glutIdleFunc(void (*func)(void)); Parameters : func - The name of the function that will be called whenever the application is idle. In our case, when the application is idle we want to call the previously defined

138 Computer Graphics and Visualization


function that does the actual rendering: renderScene. We also need to enable depth testing. By default OpenGL doesn't do this, so it doesn't know what objects are in the front and which are on the back. Unless we did draw everything in back to front order, the objects would be incorrectly drawn. Fortunately all that is required is to enable depth testing as shown in the main function below. OK, so the main function now looks like this : void main(int argc, char **argv) { glutInit(&argc, argv); // This is where we say that we want a double buffer glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("3D Tech- GLUT Tutorial"); glutDisplayFunc(renderScene); // here is the setting of the idle function glutIdleFunc(renderScene); glutReshapeFunc(changeSize); // enable depth testing glEnable(GL_DEPTH_TEST); glutMainLoop(); } Afterwards, we go and change the rendering itself. First lets declare a floating point variable angle, and initialize it to 0.0 . Then lets add the necessary stuff to the renderScene function. float angle=0.0; void renderScene(void) { // notice that we're now clearing the depth buffer // as well this is required, otherwise the depth buffer // gets filled and nothing gets rendered. // Try it out, remove the depth buffer part. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // save the previous settings, in this case save // we're refering to the camera settings. glPushMatrix();

Computer Graphics and Visualization

139

// Perform a rotation around the y axis (0,1,0) // by the amount of degrees defined in the variable angle glRotatef(angle,0.0,1.0,0.0); glBegin(GL_TRIANGLES); glVertex3f(-0.5,-0.5,0.0); glVertex3f(0.5,0.0,0.0); glVertex3f(0.0,0.5,0.0); glEnd(); // discard the modelling transformations // after this the matrix will have only the camera settings. glPopMatrix(); // swapping the buffers causes the rendering above to be // shown glutSwapBuffers(); // finally increase the angle for the next frame angle++; } The glutSwapBuffers function cause the front and back buffers to switch thereby showing what was previously drawn in the back buffer. The syntax is as follows: void glutSwapBuffers(); 1. Program to recursively subdivides a tetrahedron to from 3D Sierpinski gasket. The number of recursive steps is to be specified by the user.

#include <stdlib.h> #include <stdio.h> #include <GL/glut.h> typedef float point[3]; /* initial tetrahedron */ point v[]={{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},{-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405, -0.333333}}; static GLfloat theta[] = {0.0,0.0,0.0}; int n; void triangle( point a, point b, point c)

140 Computer Graphics and Visualization


/* display one triangle using a line loop for wire frame, a single normal for constant shading, or three normals for interpolative shading */ { glBegin(GL_POLYGON); glNormal3fv(a); glVertex3fv(a); glVertex3fv(b); glVertex3fv(c); glEnd(); } void divide_triangle(point a, point b, point c, int m) { /* triangle subdivision using vertex numbers applied to create outward pointing faces */ point v1, v2, v3; int j; if(m>0) { for(j=0; j<3; j++) for(j=0; j<3; j++) for(j=0; j<3; j++) divide_triangle(a, divide_triangle(c, divide_triangle(b, } else(triangle(a,b,c)); */ } void tetrahedron( int m) { /* Apply triangle subdivision to faces of tetrahedron */ glColor3f(1.0,1.0,1.0); divide_triangle(v[0], v[1], v[2], m); glColor3f(1.0,0.0,0.0); divide_triangle(v[3], v[2], v[1], m); glColor3f(0.0,1.0,0.0); divide_triangle(v[0], v[3], v[1], m); glColor3f(0.0,0.0,1.0); divide_triangle(v[0], v[2], v[3], m); } righthand rule

v1[j]=(a[j]+b[j])/2; v2[j]=(a[j]+c[j])/2; v3[j]=(b[j]+c[j])/2; v1, v2, m-1); v2, v3, m-1); v3, v1, m-1); /* draw triangle at end of recursion

Computer Graphics and Visualization

141

void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); tetrahedron(n); glFlush(); }

void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0); else glOrtho(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glutPostRedisplay(); }

void main(int argc, char **argv) { printf(" No. of Divisions ? "); scanf("%d",&n); glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutCreateWindow("3D Gasket"); glutReshapeFunc(myReshape); glutDisplayFunc(display); glEnable(GL_DEPTH_TEST); glClearColor (0.0, 0.0, 0.0, 0.0); glutMainLoop(); }

142 Computer Graphics and Visualization


Output :

Computer Graphics and Visualization

143

2.

Program to implement Liang-Barsky line clipping algorithm.

#include<stdio.h> #include<GL/glut.h> double xmin=50,ymin=50,xmax=100,ymax=100; double xvmin=200,yvmin=200,xvmax=300,yvmax=300; float X0,Y0,X1,Y1; int cliptest(double p,double q,double *t1,double *t2) { double t=q/p; if(p<0.0) { if(t>*t1) *t1=t; if(t>*t2) return(false); } else if(p>0.0) { if(t<*t2) *t2=t; if(t<*t2) return(false); } else if(p==0.0) { if(q<0.0) return(false); } return(true); } void LiangBarskyLineClipAndDraw(double x0,double x1,double y1) { double dx=x1-x0,dy=y1-y0,te=0.0,t1=1.0; glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(xvmin,yvmin); glVertex2f(xvmax,yvmin); glVertex2f(xvmax,yvmax); glVertex2f(xvmin,yvmax); glEnd(); if(cliptest(-dx,x0-xmin,&te,&t1)) if(cliptest(dx,xmax-x0,&te,&t1)) if(cliptest(-dy,y0-ymin,&te,&t1)) if(cliptest(dy,ymax-y0,&te,&t1)) y0,double

144 Computer Graphics and Visualization


{ if(t1<1.0) { x1=x0+t1*dx; y1=y0+t1*dy; } if(te>0.0) { x0=x0+te*dx; y0=y0+te*dy; } printf("\n%f %f : %f %f",x0,y0,x1,y1); double sx=(xvmax-xvmin)/(xmax-xmin); double sy=(yvmax-yvmin)/(ymax-ymin); double vx0=xvmin+(x0-xmin)*sx; double vy0=yvmin+(y0-ymin)*sy; double vx1=xvmin+(x1-xmin)*sx; double vy1=yvmin+(y1-ymin)*sy; glColor3f(0.0,0.0,1.0); glBegin(GL_LINES); glVertex2d(vx0,vy0); glVertex2d(vx1,vy1); glEnd(); } } void display() { //double x0=60,y0=20,x1=80,y1=120; glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex2d(X0,Y0); glVertex2d(X1,Y1); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(xmin,ymin); glVertex2f(xmax,ymin); glVertex2f(xmax,ymax); glVertex2f(xmin,ymax); glEnd(); LiangBarskyLineClipAndDraw(X0,Y0,X1,Y1); glFlush(); }

Computer Graphics and Visualization

145

void myinit() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.); glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); } void main(int argc,char **argv) { printf("Enter end points : "); scanf("%f%f%f%f",&X0,&Y0,&X1,&Y1); glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("Liang Barsky Line Clipping Algorithm"); glutDisplayFunc(display); myinit(); glutMainLoop(); } Output :

146 Computer Graphics and Visualization


3. Program to draw a color cube and spin it using OpenGL transformation matrices.

#include<stdlib.h> #include<GL/glut.h> GLfloat vertices[]={-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,1.0,-1.0, -1.0,1.0,-1.0, -1.0,-1.0,1.0, 1.0,-1.0,1.0, 1.0,1.0,1.0, -1.0,1.0,1.0}; GLfloatnormals[]={-1.0,-1.0,-1.0,1.0,-1.0,-1.0,1.0,1.0,-1.0, -1.0,1.0,-1.0,-1.0,-1.0,1.0,1.0,-1.0,1.0,1.0,1.0,1.0, -1.0,1.0,1.0}; GLfloat colors[]={0.0,0.0,0.0,1.0,0.0,0.0,1.0,1.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0,1.0,0.0,1.0,1.0, 1.0,1.0,0.0,1.0,1.0}; GLubyteCubeIndices[]={0,3,2,1,2,3,7,6,0,4,7,3,1,2,6,5,4,5,6,7, 0,1,5,4}; static GLfloat theta[]={0.0,0.0,0.0}; static GLint axis=2; void display(void) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glRotatef(theta[0],1.0,0.0,0.0); glRotatef(theta[1],0.0,1.0,0.0); glRotatef(theta[2],0.0,0.0,1.0); glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,CubeIndices); glBegin(GL_LINES); glVertex3f(0.0,0.0,0.0); glVertex3f(1.0,1.0,1.0); glEnd(); glFlush(); glutSwapBuffers(); } void spincube() { theta[axis]-=1.0; if(theta[axis]>360.0)theta[axis]-=360.0; glutPostRedisplay(); }

Computer Graphics and Visualization

147

void mouse(int btn,int state,int x,int y) { if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN) axis=0; if(btn==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN) axis=1; if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN) axis=2; } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(w<=h) { g l O r t h o ( - 2 . 0 , 2 . 0 , - 2 . 0 * ( G L f l o a t ) h / (GLfloat)w,2.0*(GLfloat)h/(GLfloat)w,-10.0,10.0); } else { glOrtho(-2.0*(GLfloat)w/(GLfloat)h,2.0*(GLfloat)w/ (GLfloat)h,-2.0,2.0,-10.0,10.0); } glMatrixMode(GL_MODELVIEW); } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutCreateWindow("Rotating Cube"); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutIdleFunc(spincube); glutMouseFunc(mouse); glEnable(GL_DEPTH_TEST); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3,GL_FLOAT,0,vertices); glColorPointer(3,GL_FLOAT,0,colors); glNormalPointer(GL_FLOAT,0,normals); glClearColor(0.0,0.0,0.0,0.0); glColor3f(1.0,1.0,1.0); glutMainLoop(); }

148 Computer Graphics and Visualization


Output :

4.

Program to create a house like figure and rotate it about a given fixed point using OpenGL functions.

#include<stdio.h> #include<math.H> #include<GL/glut.h> Glfloat house[3][9]={{150.0,150.0,225.0,300.0,300.0,200.0, 200.0,250.0,250.0},{150.0,250.0,300.0,250.0,150.0,150.0,200.0,200.0,150.0}, {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0}}; GLfloat rot_mat[3][3]={{0},{0},{0}}; GLfloat result[3][9]={{0},{0},{0}}; GLfloat h=150.0; GLfloat k=150.0; GLfloat theta; void multiply() { int i,j,l; for(i=0;i<3;i++)

Computer Graphics and Visualization

149

for(j=0;j<9;j++) { result[i][j]=0; for(l=0;l<3;l++) result[i][j]=result[i][j]+rot_mat[i][l]*house[l][j]; } } void rotate() { GLfloat m,n; m=-h*(cos(theta)-1)+k*(sin(theta)); n=-k*(cos(theta)-1)-h*(sin(theta)); rot_mat[0][0]=cos(theta); rot_mat[0][1]=-sin(theta); rot_mat[0][2]=m; rot_mat[1][0]=sin(theta); rot_mat[1][1]=cos(theta); rot_mat[1][2]=n; rot_mat[2][0]=0; rot_mat[2][1]=0; rot_mat[2][2]=1; multiply(); }

void drawhouse() { glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(house[0][0],house[1][0]); glVertex2f(house[0][1],house[1][1]); glVertex2f(house[0][3],house[1][3]); glVertex2f(house[0][4],house[1][4]); glEnd(); glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(house[0][5],house[1][5]); glVertex2f(house[0][6],house[1][6]); glVertex2f(house[0][7],house[1][7]); glVertex2f(house[0][8],house[1][8]); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(house[0][1],house[1][1]);

150 Computer Graphics and Visualization


glVertex2f(house[0][2],house[1][2]); glVertex2f(house[0][3],house[1][3]); glEnd(); }

void drawrotatedhouse() { glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(result[0][0],result[1][0]); glVertex2f(result[0][1],result[1][1]); glVertex2f(result[0][3],result[1][3]); glVertex2f(result[0][4],result[1][4]); glEnd(); glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(result[0][5],result[1][5]); glVertex2f(result[0][6],result[1][6]); glVertex2f(result[0][7],result[1][7]); glVertex2f(result[0][8],result[1][8]); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(result[0][1],result[1][1]); glVertex2f(result[0][2],result[1][2]); glVertex2f(result[0][3],result[1][3]); glEnd(); }

void display() { glClear(GL_COLOR_BUFFER_BIT); drawhouse(); rotate(); drawrotatedhouse(); glFlush(); }

void myinit() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glPointSize(1.0);

Computer Graphics and Visualization

151

glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); }

void main(int argc,char **argv) { printf("Enter the rotation angle\n"); scanf("%f",&theta); theta=theta*(3.14/180); glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("house rotation"); glutDisplayFunc(display); myinit(); glutMainLoop(); } Output :

152 Computer Graphics and Visualization


5. Program to implement the Cohen-Sutherland line-clipping algorithm. Make provision to specify the input line, window for clipping and view port for displaying the clipped image.

#include<stdio.h> #include<GL/glut.h> #define outcode int double xmin=50,ymin=50,xmax=100,ymax=100; double xvmin=200,yvmin=200,xvmax=300,yvmax=300; float X0,Y0,X1,Y1; const int RIGHT=2; const int LEFT=1; const int TOP=8; const int BOTTOM=4; outcode ComputeOutCode(double x,double y); void CohenSutherlandLineClipAndDraw(double x0,double y0,double x1,double y1) { outcode outcode0,outcode1,outcodeOut; bool accept=false,done=false; outcode0=ComputeOutCode(x0,y0); outcode1=ComputeOutCode(x1,y1); do { if(!(outcode0 | outcode1)) { accept=true; done=true; } else if(outcode0 & outcode1) done=true; else { double x,y,m; m=(y1-y0)/(x1-x0); outcodeOut=outcode0?outcode0:outcode1; if(outcodeOut & TOP) { x=x0+(ymax-y0)/m; y=ymax; } else if(outcodeOut & BOTTOM)

Computer Graphics and Visualization

153

{ x=x0+(ymin-y0)/m; y=ymin; } else if(outcodeOut & RIGHT) { y=y0+(xmax-x0)*m; x=xmax; } else { y=y0+(xmin-x0)*m; x=xmin; } if(outcodeOut == outcode0) { x0=x; y0=y; outcode0=ComputeOutCode(x0,y0); } else { x1=x; y1=y; outcode1=ComputeOutCode(x1,y1); } } }while(!done); glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(xvmin,yvmin); glVertex2f(xvmax,yvmin); glVertex2f(xvmax,yvmax); glVertex2f(xvmin,yvmax); glEnd(); printf("\n%f %f : %f %f",x0,y0,x1,y1); if(accept) { double sx=(xvmax-xvmin)/(xmax-xmin); double sy=(yvmax-yvmin)/(ymax-ymin); double vx0=xvmin+(x0-xmin)*sx; double vy0=yvmin+(y0-ymin)*sy; double vx1=xvmin+(x1-xmin)*sx; double vy1=yvmin+(y1-ymin)*sy; glColor3f(0.0,0.0,1.0); glBegin(GL_LINES);

154 Computer Graphics and Visualization


glVertex2d(vx0,vy0); glVertex2d(vx1,vy1); glEnd(); } } outcode ComputeOutCode(double x,double y) { outcode code=0; if(y>ymax) code|=TOP; else if(y<ymin) code|=BOTTOM; if(x>xmax) code|=RIGHT; else if(x<xmin) code|=LEFT; return code; } void display() { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex2d(X0,Y0); glVertex2d(X1,Y1); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(xmin,ymin); glVertex2f(xmax,ymin); glVertex2f(xmax,ymax); glVertex2f(xmin,ymax); glEnd(); CohenSutherlandLineClipAndDraw(X0,Y0,X1,Y1); glFlush(); } void myinit() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); }

Computer Graphics and Visualization

155

void main(int argc,char** argv) { printf("Enter end points : "); scanf("%f%f%f%f",&X0,&Y0,&X1,&Y1); glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("Cohen Sutherland Line Clipping Algorithm"); glutDisplayFunc(display); myinit(); glutMainLoop(); } Output :

6.

Program to create a cylinder and a parallelepiped by extruding a circle and quadrilateral respectively. Allow the user to specify the circle and the quadrilateral.

#include<stdio.h> #include<GL/glut.h> #include<math.h>

156 Computer Graphics and Visualization


void d_pixel(GLint cx,GLint cy) { glColor3f(1.0,0.0,0.0); glBegin(GL_POINTS); glVertex2f(cx,cy); glEnd(); } void plotpixels(GLint h,GLint k,GLint x,GLint y) { d_pixel(x+h,y+k); d_pixel(-x+h,-y+k); d_pixel(x+h,-y+k); d_pixel(-x+h,y+k); d_pixel(y+h,x+k); d_pixel(-y+h,x+k); d_pixel(y+h,-x+k); d_pixel(-y+h,-x+k); } void circle_draw(GLint h,GLint k,GLint r) { GLint d=1-r,x=0,y=r; while(y>x) { plotpixels(h,k,x,y); if(d<0) d+=2*x+3; else { d+=2*(x-y)+5; --y; } ++x; } plotpixels(h,k,x,y); } void cylinder_draw() { GLint xc=100,yc=100,r=50; GLint i,n=50; for(i=0;i<n;i+=3) { circle_draw(xc,yc+i,r); } }

Computer Graphics and Visualization

157

void parallelopiped(int x1,int x2,int y1,int y2) { glColor3f(0.0,0.0,1.0); glPointSize(2.0); glBegin(GL_LINE_LOOP); glVertex2i(x1,y1); glVertex2i(x1,y2); glVertex2i(x2,y2); glVertex2i(x2,y1); glEnd(); } void parallelopiped_draw() { int x1=200,x2=300,y1=100,y2=175; GLint i,n=40; for(i=0;i<n;i+=2) { parallelopiped(x1+i,x2+i,y1+i,y2+i); } } void myinit(void) { glMatrixMode(GL_PROJECTION); gluOrtho2D(0.0,499.0,0.0,499.0); } void display(void) { glColor3f(1.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); glClearColor(1.0,1.0,1.0,1.0); glPointSize(2.0); cylinder_draw(); parallelopiped_draw(); glFlush(); } void main(int argc,char** argv) { glutInit(&argc,argv); glutInitWindowPosition(0,0); glutInitWindowSize(500,500); glutCreateWindow("cylinder and parallelopiped display by xtruding circle and quadrilateral");

158 Computer Graphics and Visualization


myinit(); glutDisplayFunc(display); glutMainLoop(); } Output :

7.

Program, using OpenGL functions, to draw a simple shaded scene consisting of a tea pot on a table. Define suitably the position and properties of the light source along with the properties of the properties of the surfaces of the solid object used in the scene.

#include<stdio.h> #include<GL/glut.h> void wall(double thickness) { //draw thin wall with top=xz-plan,corner at orgin glPushMatrix(); glTranslated(0.5,0.5*thickness,0.5); glScaled(1.0,thickness,1.0); glutSolidCube(1.0); glPopMatrix(); }

Computer Graphics and Visualization

159

//draw one table leg void tableLeg(double thick,double len) { glPushMatrix(); glTranslated(0,len/2,0); glScaled(thick,len,thick); glutSolidCube(1.0); glPopMatrix(); } void table(double topWid,double topThick,double legThick,double legLen) { //draw the table -a top and four legs //draw the top first glPushMatrix(); glTranslated(0,legLen,0); glScaled(topWid,topThick,topWid); glutSolidCube(1.0); glPopMatrix(); double dist=0.95*topWid/2.0 - legThick/2.0; glPushMatrix(); glTranslated(dist,0,dist); tableLeg(legThick,legLen); glTranslated(0.0,0.0,-2*dist); tableLeg(legThick,legLen); glTranslated(-2*dist,0,2*dist); tableLeg(legThick,legLen); glTranslated(0,0,-2*dist); tableLeg(legThick,legLen); glPopMatrix(); } void displaySolid(void) { //set properties of the surface material GLfloat mat_ambient[]={1.0f,0.0f,0.0f,0.0f};//gray GLfloat mat_diffuse[]={0.5f,0.5f,0.5f,1.0f}; GLfloat mat_specular[]={1.0f,1.0f,1.0f,1.0f}; GLfloat mat_shininess[]={50.0f}; glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); //set the light source properties GLfloat lightIntensity[]={0.9f,0.9f,0.9f,1.0f};

160 Computer Graphics and Visualization


GLfloat light_position[]={2.0f,6.0f,3.0f,0.0f}; glLightfv(GL_LIGHT0,GL_POSITION,light_position); glLightfv(GL_LIGHT0,GL_DIFFUSE,lightIntensity); //set the camera glMatrixMode(GL_PROJECTION); glLoadIdentity(); double winHt=1.0;//half-height of window glOrtho(-winHt*64/48.0,winHt*64/48.0,-winHt,winHt,0.1,100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(2.3,1.3,2.0,0.0,0.25,0.0,0.0,1.0,0.0); //start drawing glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslated(0.4,0.4,0.6); glRotated(45,0,0,1); glScaled(0.08,0.08,0.08); glPopMatrix(); glPushMatrix(); glTranslated(0.4,0.38,0.4); glRotated(30,0,1,0); glutSolidTeapot(0.08); glPopMatrix(); /*glPushMatrix(); glTranslated(0.25,0.42,0.35); glutSolidSphere(0.1,15,15); glPopMatrix();*/ glPushMatrix(); glTranslated(0.4,0,0.4); table(0.6,0.02,0.02,0.3); glPopMatrix(); wall(0.02); glPushMatrix(); glRotated(90.0,0.0,0.0,1.0); wall(0.02); glPopMatrix(); glPushMatrix(); glRotated(-90.0,1.0,0.0,0.0); wall(0.02);

Computer Graphics and Visualization

161

glPopMatrix(); glFlush(); } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(640,480); glutInitWindowPosition(100,100); glutCreateWindow("SIMPLE SHADED SCENE CONSISTING OF A TEA POT ON A TABLE"); glutDisplayFunc(displaySolid); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glClearColor(0.1,0.1,0.1,0.0); glViewport(0,0,640,480); glutMainLoop(); } Output :

162 Computer Graphics and Visualization


8. Program to draw a color cube and allow the user to move the camera suitably to experiment with perspective viewing. Use OpenGL functions.

#include<stdio.h> #include<stdlib.h> #include<GL/glut.h> GLfloat vertices[][3]={{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0},{-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},{1.0,-1.0,1.0}, {1.0,1.0,1.0},{-1.0,1.0,1.0}}; GLfloat normals[][3]={{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0},{-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},{1.0,-1.0,1.0}, {1.0,1.0,1.0},{-1.0,1.0,1.0}}; GLfloat colors[][3]={{0.0,0.0,0.0},{1.0,0.0,0.0}, {1.0,1.0,0.0},{0.0,1.0,0.0}, {0.0,0.0,1.0},{1.0,0.0,1.0}, {1.0,1.0,1.0},{0.0,1.0,1.0}}; void polygon(int a,int b,int c,int d) { glBegin(GL_POLYGON); glColor3fv(colors[a]); glNormal3fv(normals[a]); glVertex3fv(vertices[a]); glColor3fv(colors[b]); glNormal3fv(normals[b]); glVertex3fv(vertices[b]); glColor3fv(colors[c]); glNormal3fv(normals[c]); glVertex3fv(vertices[c]); glColor3fv(colors[d]); glNormal3fv(normals[d]); glVertex3fv(vertices[d]); glEnd(); } void colorcube() { polygon(0,3,2,1); polygon(2,3,7,6); polygon(0,4,7,3); polygon(1,2,6,5); polygon(4,5,6,7); polygon(0,1,5,4); }

Computer Graphics and Visualization

163

static GLfloat theta[]={0.0,0.0,0.0}; static GLint axis=2; static GLdouble viewer[]={0.0,0.0,5.0}; void display() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); gluLookAt(viewer[0],viewer[1],viewer[2],0.0,0.0,0.0,0.0,1.0,0.0); glRotatef(theta[0],1.0,0.0,0.0); glRotatef(theta[1],0.0,1.0,0.0); glRotatef(theta[2],0.0,0.0,1.0); colorcube(); glFlush(); glutSwapBuffers(); } void mouse(int btn,int state,int x,int y) { if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN) axis=0; if(btn==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN) axis=1; if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN) axis=2; theta[axis]+=2.0; if(theta[axis]>360.0)theta[axis]-=360.0; display(); } void keys(unsigned char key,int x,int y) { if(key=='x') viewer[0]-=1.0; if(key=='X') viewer[0]+=1.0; if(key=='y') viewer[1]-=1.0; if(key=='Y') viewer[1]+=1.0; if(key=='z') viewer[2]-=1.0; if(key=='Z') viewer[2]+=1.0; display(); } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(w<=h) { glFrustum(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w,2.0*

164 Computer Graphics and Visualization


(GLfloat)h/(GLfloat)w,2.0,20.0); } else { glFrustum(-2.0,2.0,-2.0*(GLfloat)w/(GLfloat)h, 2.0*(GLfloat)w/(GLfloat)h,2.0,20.0); } glMatrixMode(GL_MODELVIEW); } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutCreateWindow("Color Cube Viewer"); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutMouseFunc(mouse); glutKeyboardFunc(keys); glEnable(GL_DEPTH_TEST); glutMainLoop(); } Output :

Computer Graphics and Visualization

165

9.

Program to fill any given polygon using scan-line area filling algorithm. (Use appropriate data structures.)

#include <stdlib.h> #include <stdio.h> #include <GL/glut.h> float x1,x2,x3,x4,y1,y2,y3,y4; void edgedetect(float x1,float y1,float x2,float y2,int *le,int *re) { float mx,x,temp; int i; if((y2-y1)<0) { temp=y1;y1=y2;y2=temp; temp=x1;x1=x2;x2=temp; } if((y2-y1)!=0) mx=(x2-x1)/(y2-y1); else mx=x2-x1; x=x1; for(i=y1;i<=y2;i++) { if(x<(float)le[i]) le[i]=(int)x; if(x>(float)re[i]) re[i]=(int)x; x+=mx; } } void draw_pixel(int x,int y,int value) { glColor3f(0.7,0.5,0.8); glBegin(GL_POINTS); glVertex2i(x,y); glEnd(); } void scanfill(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4) { int le[500],re[500];

166 Computer Graphics and Visualization


int i,y; for(i=0;i<500;i++) { le[i]=500; re[i]=0; } edgedetect(x1,y1,x2,y2,le,re); edgedetect(x2,y2,x3,y3,le,re); edgedetect(x3,y3,x4,y4,le,re); edgedetect(x4,y4,x1,y1,le,re); for(y=0;y<500;y++) { if(le[y]<=re[y]) for(i=(int)le[y];i<(int)re[y];i++) draw_pixel(i,y,BLACK); } } void display() { x1=200.0;y1=200.0;x2=100.0;y2=300.0;x3=200.0;y3=400.0;x4=300.0;y4=300.0; glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); glBegin(GL_LINE_LOOP); glVertex2f(x1,y1); glVertex2f(x2,y2); glVertex2f(x3,y3); glVertex2f(x4,y4); glEnd(); scanfill(x1,y1,x2,y2,x3,y3,x4,y4); glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex2f(x1,y1); glVertex2f(x2,y2); glEnd(); glColor3f(1.0,0.0,0.0); glBegin(GL_LINES); glVertex2f(x2,y2); glVertex2f(x3,y3); glEnd(); glFlush(); } void myinit() {

Computer Graphics and Visualization

167

glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); } void main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("Filling a Polygon using Algorithm"); glutDisplayFunc(display); myinit(); glutMainLoop(); } Output :

Scan-line

168 Computer Graphics and Visualization


10. Program to display a set of values { fij } as a rectangular mesh. #include<stdlib.h> #include<GL/glut.h> #define #define #define #define maxx 25 maxy 25 dx 15 dy 10

GLfloat x[maxx]={0.0},y[maxy]={0.0}; GLfloat x0=50,y0=50; int i,j; void init() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glPointSize(5.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); glutPostRedisplay(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0,0.0,1.0); for(i=0;i<maxx;i++) x[i]=x0+i*dx; for(j=0;j<maxy;j++) y[j]=y0+j*dy; glColor3f(0.0,1.0,0.0); for(i=0;i<maxx-1;i++) for(j=0;j<maxy-1;j++) { glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(x[i],y[j]); glVertex2f(x[i],y[j+1]); glVertex2f(x[i+1],y[j+1]); glVertex2f(x[i+1],y[j]); glEnd(); glFlush(); }

Computer Graphics and Visualization

169

glFlush(); } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,400); glutCreateWindow("rectangular mesh"); glutDisplayFunc(display); init(); glutMainLoop(); } Output :

Anda mungkin juga menyukai