LP PR1 21IT033 Merged
LP PR1 21IT033 Merged
PRACTICAL: 1
AIM:
Write a ‘C’ program and generate the following codes for the program.
1) Preprocessed code
2) Assembly Code
3) Object Code
4) Executable Code
THEORY:
1. Preprocessed Code
Definition: The preprocessed code is the output of the C preprocessor, which is the first
stage of the compilation process.
Purpose: The preprocessor handles directives like #include, #define, and #ifdef. It replaces
macros, includes the contents of header files, and processes conditional compilation
directives.
Result: The result is a .i file (or sometimes .ii for C++) that contains the expanded source
code with all preprocessing directives resolved. It’s still in C language, but with all macros
expanded and header files included.
2. Assembly Code
3. Object Code
Definition: Object code is the machine code generated from the assembly code but is not yet
fully linked into a complete program.
Purpose: This stage translates assembly code into machine code, which is a binary
representation of the program instructions that the CPU can execute. However, at this stage,
it’s not yet a complete executable; it may still contain unresolved references (e.g., calls to
external functions).
Result: The output is a .o (or .obj) file that contains binary machine code. This file is not
directly executable but is ready to be linked with other object files and libraries.
CSPIT-IT Page | 1
21IT033 IT443:LP
4. Executable Code
Definition: Executable code is the final output of the compilation process, ready to be run on
the system.
Purpose: The linker combines all the object files and resolves all references between them.
It links the object code with any required libraries and generates a complete, executable
program.
Result: The result is an executable file (e.g., a.out on Unix-like systems or .exe on
Windows). This file can be directly executed by the operating system to run the program.
CODE:
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
To generate the preprocessed code, use the gcc command with the -E option:
This command will create a file named hello.i containing the preprocessed code.
To generate the assembly code, use the gcc command with the -S option:
This command will produce a file named hello.s containing the assembly code.
CSPIT-IT Page | 2
21IT033 IT443:LP
To generate the object code, use the gcc command with the -c option:
This will create a file named hello.o containing the object code.
Finally, to generate the executable code, use the gcc command without any additional
options:
OUTPUT:
./hello
This will output:
Hello, World!
CSPIT-IT Page | 3
21IT033 IT443:LP
LEARNING OUTCOME:
Preprocessed Code (.i): Expanded C code after handling directives and macros.
Assembly Code (.s): Low-level assembly language version of the C code.
Object Code (.o): Machine code not yet linked into a complete program.
Executable Code: The final runnable program after linking all object files and libraries.
CSPIT-IT Page | 4
21IT033 IT443:LP
PRACTICAL: 2
AIM:
1) Simple Macro
3) Nested Macro
THEORY:
1. Simple Macro
Definition: A simple macro is a basic form of macro substitution where a symbolic name (macro
name) is defined to represent a constant value or an expression. The C preprocessor performs this
substitution before the actual compilation of the code.
Usage:
Explanation: When the preprocessor encounters PI in the code, it replaces it with 3.14159. This can
make the code easier to maintain and read, as changing the value of PI in one place (the #define
directive) updates it everywhere it’s used.
Advantages:
Ease of Maintenance: Changes to the macro’s value or expression are reflected throughout
the codebase without needing to modify each instance manually.
Code Clarity: Provides meaningful names for constants or expressions, improving code
readability.
Definition: A macro with arguments allows you to create more complex macros that can take
parameters. This is akin to a function, but with the expansion occurring at preprocessing time rather
than runtime.
CSPIT-IT Page | 1
21IT033 IT443:LP
Usage:
Explanation: When SQUARE(5) is used in the code, it is replaced by ((5) * (5)). This macro can be
used to compute the square of any value passed to it. The use of parentheses ensures correct
evaluation order and avoids potential issues with operator precedence.
Advantages:
Reusability: Allows for the creation of reusable code templates that can operate on different
data values.
Efficiency: Like functions, they can reduce code duplication, but unlike functions, they do
not incur a function call overhead.
3. Nested Macro
Definition: Nested macros involve using one macro within the definition of another macro. This
allows for complex macro definitions that build on simpler ones.
Usage:
#define PI 3.14159
#define CIRCUMFERENCE(radius) (2 * PI * (radius))
Explanation: Here, CIRCUMFERENCE(radius) uses the PI macro within its definition. When the
macro CIRCUMFERENCE(5) is invoked, it expands to 2 * 3.14159 * 5. Nested macros enable the
creation of complex expressions while leveraging simpler macros.
Advantages:
A simple macro is a straightforward substitution where a single identifier is replaced with a constant
value or expression.
Example:
CSPIT-IT Page | 2
21IT033 IT443:LP
#include <stdio.h>
#define PI 3.14159
int main() {
printf("The value of PI is: %f\n", PI);
return 0;
}
In this example, the #define PI 3.14159 line defines a simple macro named PI. Every occurrence of
PI in the code is replaced by 3.14159 before the code is compiled.
A macro with arguments allows you to define a macro that takes parameters, similar to a function.
This is useful for operations that require input values.
Example:
#include <stdio.h>
int main() {
int num = 5;
printf("The square of %d is: %d\n", num, SQUARE(num));
return 0;
}
In this example, SQUARE(x) is a macro that computes the square of x. When SQUARE(num) is
used, it expands to ((num) * (num)).
3. Nested Macro
A nested macro involves one macro invoking another macro. This allows for more complex
operations and code reuse.
Example:
#include <stdio.h>
#define PI 3.14159
#define CIRCUMFERENCE(radius) (2 * PI * (radius))
int main() {
double radius = 5.0;
printf("The circumference of a circle with radius %.2f is: %.2f\n", radius,
CIRCUMFERENCE(radius));
return 0;
}
CSPIT-IT Page | 3
21IT033 IT443:LP
In this example, the CIRCUMFERENCE(radius) macro uses the PI macro inside its definition. The
CIRCUMFERENCE(radius) macro calculates the circumference of a circle using the value of PI and
the given radius.
LEARNING OUTCOME:
Simple Macro: Replaces an identifier with a constant value or expression.
Macro with Argument: Defines a macro that takes parameters and performs operations.
Nested Macro: Uses one macro within another macro to create more complex expressions or
operations.
CSPIT-IT Page | 4
21IT033 IT443:LP
PRACTICAL: 3
AIM:
Write a Lexical Analyzer using Lex or Flex utility of UNIX for following:
THEORY:
Lexical Analysis is the first phase of a compiler or an interpreter, responsible for reading the source
code and converting it into a sequence of tokens. A token is the smallest unit of meaning in a
programming language, such as keywords, identifiers, operators, literals, etc.
2. What is Lex/Flex?
Lex is a tool used for generating lexical analyzers (scanners) in C programming language. It was
developed as part of the UNIX operating system, and Flex (Fast Lex) is an open-source
implementation of Lex.
CSPIT-IT Page | 1
21IT033 IT443:LP
Lex/Flex works by taking a set of regular expressions as input (called patterns) and generating a C
function, yylex(), which can recognize tokens based on those patterns. The typical output of
Lex/Flex is a C program that reads an input stream and breaks it into meaningful sequences, i.e.,
tokens.
1. Definition Section: Contains C code, global variable declarations, and #include directives.
shell
Copy code
%{
C code and declarations
%}
2. Rules Section: Contains patterns (regular expressions) and actions. Patterns are matched
against the input stream, and when a match is found, the corresponding action is executed.
shell
Copy code
%%
pattern1 { action1 }
pattern2 { action2 }
%%
3. User Code Section: Contains the main() function and any additional C code required to run
the lexical analyzer.
javascript
Copy code
%%
main() {
// User Code
}
Input: The input to the lexer is a stream of characters, typically the source code.
Pattern Matching: The lexer matches sequences of characters with patterns defined in
regular expressions.
Token Generation: Once a pattern is matched, it executes an associated action, such as
generating a token or printing the matched pattern.
Output: The output of a lexer is a sequence of tokens or actions performed on the matched
input, such as counting words, lines, or extracting numbers.
CSPIT-IT Page | 2
21IT033 IT443:LP
6. Actions:
Actions are C statements that define what happens when a pattern is matched. Common actions
include:
yylex(): This is the main function generated by Lex. It reads the input, matches patterns,
and executes actions.
yytext: A global variable in Lex that stores the matched input string for the current token.
yyleng: A global variable that holds the length of the string stored in yytext.
%{
#include <stdio.h>
%}
%%
%%
int main() {
yylex();
return 0;
}
%{
#include <stdio.h>
CSPIT-IT Page | 3
21IT033 IT443:LP
%}
%%
%%
int main() {
yylex();
return 0;
}
%{
#include <stdio.h>
int vowels = 0;
int consonants = 0;
%}
%%
[aAeEiIoOuU] { vowels++; }
[b-df-hj-np-tv-zB-DF-HJ-NP-TV-Z] { consonants++; }
[ \t\n] ; // Ignore whitespace
. ; // Ignore other characters
%%
int main() {
yylex();
printf("Vowels: %d\n", vowels);
printf("Consonants: %d\n", consonants);
return 0;
}
%{
#include <stdio.h>
int line_num = 1;
%}
%%
\n { printf("%d: %s", line_num++, yytext); } // Increment and print line number for each
new line
CSPIT-IT Page | 4
21IT033 IT443:LP
%%
int main() {
yylex();
return 0;
}
%{
#include <stdio.h>
%}
%%
%%
int main() {
yylex();
return 0;
}
%{
#include <stdio.h>
int char_count = 0;
int word_count = 0;
int line_count = 0;
%}
%%
%%
int main() {
yylex();
printf("Lines: %d\n", line_count);
CSPIT-IT Page | 5
21IT033 IT443:LP
bash
Copy code
flex lexer.l
gcc lex.yy.c -lfl
./a.out < input.txt
LEARNING OUTCOME:
From this practical I will come to learn about how to use Lex/Flex to generate lexical
analyzers for tokenizing input based on regular expressions.
Understand how to classify, count, and process different token types like numbers, words,
and special characters efficiently.
CSPIT-IT Page | 6
IT443 Language Processor 7IT
Practical 4
Aim:
Implement
Lexical analyzer for C language using lex.
Program:
%{
#include <stdio.h>
#include
<string.h>
char *keywords[] = { "int", "float", "char", "double", "if", "else", "while", "for", "return", "void", NULL
%%
[ \t\n]+
"int"|"float"|"char"|"double"|"if"|"else"|"while"|"for"|"return"|"void" { printf("Keyword: %s\n", yytext); }
"\/\/".* { printf("Single-line Comment: %s\n", yytext); }
"\/\*"([^*]|\*+[^*/])*\*+\/ { printf("Multi-line Comment: %s\n", yytext);
} [a-zA-Z_][a-zA-Z0-9_]* {
if (is_keyword(yytext))
printf("Keyword: %s\n", yytext);
else
printf("Identifier: %s\n", yytext);
}
[0-9]+ { printf("Integer Constant: %s\n", yytext); }
[0-9]+"."[0-9]+ { printf("Floating Constant: %s\n", yytext); }
"+"|"-"|"*"|"/"|"="|"=="|"!=" { printf("Operator: %s\n", yytext); }
"{"|"}"|"("|")"|"["|"]" { printf("Punctuation: %s\n", yytext); }
. { printf("Unknown Character: %s\n", yytext); }
%%
int main()
{
yylex();
return 0;
}
21IT033 1
IT443 Language Processor 7IT
int yywrap()
{ return 1;
}
Output:
21IT033 2
IT443 Language Processor 7IT
Conclusion:
In this practical, I developed a lexical analyzer for the C language using Lex/Flex. By defining
regular expressions, I was able to identify different components of a C program, including
keywords, identifiers, operators, constants, and comments. I also successfully implemented
pattern matching to manage both single-line and multi-line comments. This practical highlighted
the critical role regular expressions play in lexical analysis and showcased how Lex/Flex
streamlines the process of generating efficient C code for tokenizing input. It gave me valuable
insights into the initial phase of source code translation in compilers and interpreters.
21IT033 3
IT443 Language Processor 7IT (July-Dec 2024)
Practical 5
Aim:
Write a program that enters Transition Table, accepting state and input string as input
and checks whether the given string is accepted or not.
Program:
return state in
row = []
for j in range(num_inputs):
")) row.append(next_state)
transition_table.append(row)
for char in
input_string:
input_symbol =
int(char)
print("Invalid input
detected!") return
current_state =
transition_table[current_state][input_symbol] if
is_accepting_state(current_state, accepting_states):
print("The string is
accepted.") else:
main ":
main()
Output:
21IT033 Page 2
IT443 Language Processor 7IT (July-Dec 2024)
Output of DFA
Conclusion:
In this practical, I created a Python program to simulate a Deterministic Finite Automaton (DFA). The program
enables me to:
Provide User Inputs:
o Transition Table: I can define the state transitions of the DFA based on each input symbol.
o Initial State: I specify the DFA's starting state.
o Accepting States: I select the states that indicate acceptance of the input string.
o Input String: I input the string that the DFA will evaluate.
21IT033 Page 3
IT443 Language Processor 7IT (July-Dec 2024)
21IT033 Page 4
IT443 Language Processors CSPIT 7IT (2024-2025)
Practical 6
Aim:
Explore the JFLAP Tool to demonstrate the deterministic finite
automata for following also find its Regular expression.
1) Odd number of 0’a or Even number of 1’s
2) Odd number of 0’a and Even number of 1’s
21IT033 1
IT443 Language Processors CSPIT 7IT (2024-2025)
Regular Expression:
21IT033 2
IT443 Language Processors CSPIT 7IT (2024-2025)
21IT033 3
IT443 Language Processors CSPIT 7IT (2024-2025)
Regular Expression:
Learning Outcome:
Through this practical, I gained experience in constructing deterministic finite automata
(DFAs) using the JFLAP tool to handle conditions such as an odd number of 0's or an even
number of 1's. I enhanced my ability to formulate regular expressions, test input strings, and
evaluate the criteria for acceptance and rejection. This exercise significantly improved my
understanding of automata theory and its practical applications in computer science.
21IT033 4
IT443 Language Processors CSPIT 7IT (2024-2025)
Practical 7
Aim:
Create Google Form for the student registration with student ID, Name, Email Address,
Mobile number etc. Provide Regular expression in every field of the Google Form.
Program:
Student ID – ^[A-Za-z0-9]{8}$
Student Name – ^[A-Za-z\s]+$
Mobile Number - ^\d{10}$
Email ID – ^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$
21IT033 Page 1
IT443 Language Processors CSPIT 7IT (2024-2025)
21IT033 Page 2
IT443 Language Processors CSPIT 7IT (2024-2025)
21IT033 Page 3
IT443 Language Processors CSPIT 7IT (2024-2025)
Learning Outcome:
I learned how to validate user inputs in a Google Form using regular expressions. This
involved designing regex patterns for fields like phone numbers, email addresses to ensure
the data adheres to predefined formats, improving the accuracy and reliability of form
submissions.
21IT033 Page 4
IT443 Language Processor 7IT (July-Dec 2024)
Practical 8
Aim:
Theory:
Applications of TAC:
Language translation: Three address codes can also be used to translate code from
one programming language to another. By translating code to a common intermediate
representation, it becomes easier to translate the code to multiple target languages.
Program:
TAC:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
char expression[100];
// Generate TAC
printf("Three Address Code for the given expression:\n");
generateTAC(expression);
return 0;
}
Output:
Conclusion:
In this Practical, I learned that the generation of Three Address Code (TAC) in C
programming is a fundamental aspect of compiler design, as it transforms complex
expressions into a more manageable format that can be optimized and converted into
machine code.
Practical 9
Aim:
Demonstrate the parsing technique using ANTLR Tool.
Program:
grammar Expr;
prog: (expr NEWLINE)* ;
expr: expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '**' expr
| expr '/' expr
| expr '%' expr
| INT
| '(' expr ')'
;
NEWLINE : [\r\n]+ ;
INT : [0-9]+ ;
Output:
21IT033 Page 26
3
IT443 Language Processor 7IT (July-Dec 2024)
Conclusion:
In this practical, I learned about ANTLR tool used for parsing, which can generate tokens,
generate parsing tree from the given grammar and also generate code for different languages for
the grammar.
21IT033 Page 27
3
IT443 Language Processor 7IT (July-Dec 2024)
Practical 10
Aim:
Write a Parser using YACC or utility of UNIX for following:
Write a Program for a simple desk calculator using YACC Specification.
Program:
calc.l
%option noyywrap
%{
#include "calc.tab.h"
%}
DIGIT [0-9]
WS [ \t]
%%
. { return yytext[0]; }
%%
calc.y
%{
#include <stdio.h>
#include <ctype.h>
int flag = 0;
21IT033 Page 21
IT443 Language Processor 7IT (July-Dec 2024)
%}
%token NUMBER
%left '+' '-'
%left '*' '/' '%'
%left '(' ')'
%%
ArithmeticExpression: E
{
printf("\nResult=%d\n", $1);
return 0;
};
E:
E '+' E
{
$$ = $1 + $3;
}
| E '-' E
{
$$ = $1 - $3;
}
| E '*' E
{
$$ = $1 * $3;
}
| E '/' E
{
if ($3 == 0)
{
yyerror("Division by zero");
flag = 1;
}
else
{
$$ = $1 / $3;
}
}
| E '%' E
{
$$ = $1 % $3;
}
| '(' E ')'
21IT033 Page 22
IT443 Language Processor 7IT (July-Dec 2024)
{
$$ = $2;
}
| NUMBER
{
$$ = $1;
};
%%
int main()
{
printf("Enter any arithmetic expression that can have operations (+, -, *, /, %) and round
brackets:\n");
yyparse();
if (flag == 0)
{
printf("Entered arithmetic expression is valid\n\n");
}
return 0;
}
Output:
21IT158 Page 30
IT443 Language Processor 7IT (July-Dec 2024)
Conclusion:
In this practical learned about YAAC tool and lex tool. Created the simple arithmetic calculate
using YAAC and lex.
21IT158 Page 31