0% found this document useful (0 votes)
9 views39 pages

LP PR1 21IT033 Merged

Uploaded by

Vidhi Shah
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views39 pages

LP PR1 21IT033 Merged

Uploaded by

Vidhi Shah
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

21IT033 IT443:LP

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

 Definition: Assembly code is a low-level representation of the program, generated by


translating the high-level C code.
 Purpose: This stage converts the preprocessed C code into assembly language, which is a
human-readable, low-level language specific to a particular CPU architecture.
 Result: The output is a .s file containing assembly instructions that correspond to the original
C code. This code is still somewhat readable by humans, especially those familiar with
assembly language, and is one step closer to machine 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:

Step 1: Write a simple C program

#include <stdio.h>

int main() {

printf("Hello, World!\n");

return 0;

Save this program in a file called hello.c.

Step 2: Generate the Preprocessed Code

To generate the preprocessed code, use the gcc command with the -E option:

gcc -E hello.c -o hello.i

This command will create a file named hello.i containing the preprocessed code.

Step 3: Generate the Assembly Code

To generate the assembly code, use the gcc command with the -S option:

gcc -S hello.c -o hello.s

This command will produce a file named hello.s containing the assembly code.

CSPIT-IT Page | 2
21IT033 IT443:LP

Step 4: Generate the Object Code

To generate the object code, use the gcc command with the -c option:

gcc -c hello.c -o hello.o

This will create a file named hello.o containing the object code.

Step 5: Generate the Executable Code

Finally, to generate the executable code, use the gcc command without any additional
options:

gcc hello.c -o hello

This command will produce an executable file named hello.

OUTPUT:

Preprocessed Code: hello.i

Assembly Code: hello.s

Object Code: hello.o

Executable Code: hello

TO RUN THE CODE:

./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:

Use Macro features of C language and demonstrate the following types of


macro with example.

1) Simple Macro

2) Macro with Argument

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:

 Syntax: #define MACRO_NAME value


 Example: #define PI 3.14159

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.

2. Macro with Argument

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:

 Syntax: #define MACRO_NAME(parameters) expression


 Example: #define SQUARE(x) ((x) * (x))

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:

 Syntax: Can be nested within other macros or even themselves.


 Example:

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

 Modularity: Encourages modular code by allowing complex operations to be built from


simpler components.
 Maintainability: Changes in the base macros (like PI) automatically propagate through all
dependent macros, making updates simpler.

CODE & OUTPUT


1. Simple Macro

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.

2. Macro with Argument

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>

#define SQUARE(x) ((x) * (x))

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:

1. A lexer to print out all numbers from a given file.

2. A lexer which classifies tokens as words, numbers or "other".

3. Write a Lex Program to count number of vowels and consonants.

4. A lexer which adds line numbers to thengiven file.

5. A lexer which attempt to extract only comments.

6. A lexer to do word count function of wc command in UNIX.It prints the


number of lines, words and characters in a file.

THEORY:

1. What is Lexical Analysis?

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.

3. Components of a Lex Program:

A Lex/Flex program consists of three sections:

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
}

4. Lexical Analysis Process:

The lexical analyzer works as follows:

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

5. Regular Expressions in Lex:

In Lex, regular expressions are used to specify patterns:

CSPIT-IT Page | 2
21IT033 IT443:LP

 [a-z] matches any lowercase letter.


 [0-9]+ matches one or more digits (numbers).
 . matches any single character.
 * matches zero or more occurrences of the previous character.

6. Actions:

Actions are C statements that define what happens when a pattern is matched. Common actions
include:

 Printing matched tokens: Example: printf("Number: %s\n", yytext); prints the


matched number.
 Counting: Actions can count occurrences, like counting words, characters, or lines.
 Skipping characters: You can define actions to ignore whitespace, comments, or other
characters.

7. Key Lex Functions:

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

CODE & OUTPUT:

1. Lexer to Print Out All Numbers from a Given File

%{
#include <stdio.h>
%}

%%

[0-9]+ { printf("Number: %s\n", yytext); } // Recognizes integers


[ \t\n] ; // Ignore whitespace
. ; // Ignore other characters

%%

int main() {
yylex();
return 0;
}

2. Lexer Which Classifies Tokens as Words, Numbers, or "Other"

%{
#include <stdio.h>

CSPIT-IT Page | 3
21IT033 IT443:LP

%}

%%

[0-9]+ { printf("Number: %s\n", yytext); }


[a-zA-Z]+ { printf("Word: %s\n", yytext); }
[ \t\n] ; // Ignore whitespace
. { printf("Other: %s\n", yytext); }

%%

int main() {
yylex();
return 0;
}

3. Lex Program to Count Number of Vowels and Consonants

%{
#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;
}

4. Lexer Which Adds Line Numbers to the Given File

%{
#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

. { printf("%s", yytext); } // Print other characters

%%

int main() {
yylex();
return 0;
}

5. Lexer Which Attempts to Extract Only Comments

%{
#include <stdio.h>
%}

%%

"/*"[^*]*"*"+[^/]*"*/" { printf("Comment: %s\n", yytext); } // Recognizes multi-line C style


comments
"//".* { printf("Comment: %s\n", yytext); } // Recognizes single-line C++ style
comments
. ; // Ignore other characters

%%

int main() {
yylex();
return 0;
}

6. Lexer to Perform Word Count (Equivalent to wc Command in UNIX)

%{
#include <stdio.h>

int char_count = 0;
int word_count = 0;
int line_count = 0;
%}

%%

[a-zA-Z0-9]+ { word_count++; char_count += yyleng; } // Count words and characters


\n { line_count++; char_count++; } // Count lines and characters
. { char_count++; } // Count any other characters

%%

int main() {
yylex();
printf("Lines: %d\n", line_count);

CSPIT-IT Page | 5
21IT033 IT443:LP

printf("Words: %d\n", word_count);


printf("Characters: %d\n", char_count);
return 0;
}

How to run the given file:

1. Save the code into a file with .l extension (e.g., lexer.l).


2. Use the following commands to compile and run it:

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

}; int is_keyword(char *identifier) {


int i = 0;
while (keywords[i]) {
if (strcmp(keywords[i], identifier) == 0)
return 1;
i++;
}
return 0;
}
%}

%%
[ \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:

def is_accepting_state(state, accepting_states):

return state in

accepting_states def main():

num_states = int(input("Enter the number of states: "))

num_inputs = int(input("Enter the number of input

symbols: ")) transition_table = []

print("Enter the transition table (states indexed from

0):") for i in range(num_states):

row = []

for j in range(num_inputs):

next_state = int(input(f"Transition from state {i} with input {j}:

")) row.append(next_state)

transition_table.append(row)

initial_state = int(input("Enter the initial state: ")

num_accepting = int(input("Enter the number of accepting states: "))

accepting_states = list(map(int, input("Enter the accepting states:

").split())) input_string = input("Enter the input string (without

spaces): ") current_state = initial_state

for char in

input_string:

input_symbol =

int(char)

if input_symbol >= num_inputs:


21IT033 Page 1
IT443 Language Processor 7IT (July-Dec 2024)

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:

print("The string is not

accepted.") if name == "

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)

1. Process the Input String:


○ The DFA transitions between states based on the input symbols and the transition table.
○ It ensures that the input string only contains valid symbols as defined by the DFA.
2. Determine Acceptance:
○ After processing the entire input string, the DFA checks if the resulting state is an
accepting state.
○ If the DFA ends in an accepting state, it accepts the input string. Otherwise, it rejects it.

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

Input & Output:


1) Odd number of 0’a or 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)

2) Odd number of 0’a and Even number of 1’s

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,}$

Input & Output:

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:

 Write Generation of Three Address Code in C Programming.

Theory:

 Three address code:

 TAC is an intermediate representation of three-address code utilized by compilers to


ease the process of code generation.
 Complex expressions are, therefore, decomposed into simple steps comprising, at
most, three addresses: two operands and one result using this code.
 The results from TAC are always stored in the temporary variables that a compiler
generates. This design ensures explicit ordering of the operations that come into play.

 Applications of TAC:

 Optimization: Three-address code is often used as an intermediate representation of


code during the optimization phases of the compilation process. The three-address
code allows the compiler to analyze the code and perform optimizations that can
improve the performance of the generated code.
 Code generation: Three address codes can also be used as an intermediate
representation of code during the code generation phase of the compilation process.
The three-address code allows the compiler to generate code that is specific to the
target platform, while also ensuring that the generated code is correct and efficient.
 Debugging: Three address codes can be helpful in debugging the code generated by
the compiler. Since the address code is a low-level language, it is often easier to read
and understand than the final generated code. Developers can use the three address
codes to trace the execution of the program and identify errors or issues that may be
present.

ID No. 21IT036 Page 39


IT443 Language Processor 7IT (July-Dec 2024)

 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>

// Function to generate TAC


void generateTAC(char expr[]) {
int i = 0;
char op; // Operator
char left, right, result;

// Scan the expression from left to right


while (expr[i] != '\0') {
if (isalnum(expr[i])) {
left = expr[i];
}
else if (expr[i] == '+' || expr[i] == '-' || expr[i] == '*' || expr[i] == '/') {
// Handle operator
op = expr[i];
right = expr[i + 1];

// Generate the TAC output


result = 't'; // Temporary variable prefix
result += i; // Give unique temp variable names
printf("%c = %c %c %c\n", result, left, op, right);

// Update left to hold result for next calculation


left = result;
}
i++;
}
}

int main() {
char expression[100];

ID No. 21IT036 Page 40


IT443 Language Processor 7IT (July-Dec 2024)

// Get expression input


printf("Enter an expression (like a+b*c): ");
scanf("%s", expression);

// Generate TAC
printf("Three Address Code for the given expression:\n");
generateTAC(expression);

return 0;
}

Output:

Fig-1: Output reveals an Expression from the code

ID No. 21IT036 Page 41


IT443 Language Processor 7IT (July-Dec 2024)

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.

ID No. 21IT036 Page 42


IT443 Language Processor 7IT (July-Dec 2024)

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]

%%

{DIGIT}+ { yylval = atoi(yytext); return NUMBER; }


"+" { return '+'; }
"-" { return '-'; }
"*" { return '*'; }
"/" { return '/'; }
"%" { return '%'; }
"(" { return '('; }
")" { return ')'; }
{WS} ; /* skip whitespace */

. { return yytext[0]; }

%%

calc.y

%{
#include <stdio.h>
#include <ctype.h>

int flag = 0;

extern int yylex(void);


extern void yyerror(char* msg);
extern int yylval;

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

%%

void yyerror(char* msg)


{
printf("\nError: %s\n\n", msg);
flag = 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

You might also like