0% found this document useful (0 votes)
12 views

CS3501_LABMANUAL

cs3501 lab mannual

Uploaded by

thakrishnankumu
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)
12 views

CS3501_LABMANUAL

cs3501 lab mannual

Uploaded by

thakrishnankumu
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/ 23

CSI THOOTHUKUDI-NAZARETH DIOCESE

DR.G.U.POPE COLLEGE OF ENGINEERING


POPE NAGAR SAWYERPURAM-628 251

Register No :

Certified that this is the bonafide record of work done by


Selvan/Selvi ……………………………………………………………………………….…....

of ………. Semester ……….. branch for the lab …………………………………………....

During the academic year ……………………………

Staff In-charge H. O .D

Submitted for the university practical Examination held on ……………………….

Internal Examiner External Examiner


S.NO TOPIC PAGE.NO MARKS SIGNATURE

1.

2.

3a.

3b.

3c.

3d.

4.

5.

6.

7.
EX NO :01
DATE : DEVELOP A LEXICAL ANALYZER TO RECOGNIZE A FEW PATTERNS IN C

AIM:
To develop a lexical analyzer to identify identifiers,constants,comments,operators etc using C
program

ALGORITHM:

STEP 1 : Initialize input string and pointer.


STEP 2 : Loop through the input string.
STEP 3 : Skip whitespace, identify if the current character is an identifier, number, or
operator/unknown.
STEP 4 : Print the identified token type.
STEP 5 : Repeat until the end of the string is reached.

PROGRAM:

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

void printToken(char *type, char *value){


printf("%s: %s\n", type, value);
}

void getNextToken(char **input) {


char token[100];
int i = 0;
while (isspace(**input)) (*input)++;
if (isalpha(**input)) {
while (isalpha(**input) || isdigit(**input)) token[i++] = *(*input)++;
printToken("IDENTIFIER", token);
}
else if (isdigit(**input)) { while (isdigit(**input)) token[i++] = *(*input)++;
printToken("NUMBER",token);
}
else if (**input != '\0') { token[i++] = *(*input)++;
printToken("OPERATOR/UNKNOWN", token);
}
token[i] = '\0';
}

int main() {
char input[] = "int a = 5 + 3;", *ptr = input;
while (*ptr != '\0') getNextToken(&ptr);
return 0;
}

1
OUTPUT :

RESULT:

Thus the program for lexical analyzer to recognize a few patterns program in C has been
successfully executed.

2
EX NO :02
IMPLEMENTATION OF LEXICAL ANALYZER USING LEX TOOL
DATE :

AIM:
To develop the lex to extract tokens from a given source code.

ALGORITHM :

STEP 1 :Check for the lexical tool version before working.


STEP 2 :If not installed , install it using the prefered commands.
STEP 3 :Feed your program to the code editor , covert it into lexical program using lex command.
STEP 4 :Compile your program using special lexical compiler which would be installed with your
lex analyzer.
STEP 5 :Run the program, execute by the lexical tool and observe your output.

PROGRAM:

Installation - sudo apt-get install flex


Version - yacc --version
Flex file - <file name>.l
Flex Generate - flex <filename.l>
Compilation - gcc lex.yy.c
Run - ./a.out

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

void yyerror(const char *s);


int yylex(void);
%}

%%
[0-9]+ { printf("NUMBER: %s\n", yytext); }
[a-zA-Z_][a-zA-Z0-9_]* { printf("IDENTIFIER: %s\n", yytext); }
"+" { printf("PLUS\n"); }
"-" { printf("MINUS\n"); }
"*" { printf("MULTIPLY\n"); }
"/" { printf("DIVIDE\n"); }
\n { /* Ignore newline */ }
[ \t]+ { /* Ignore whitespace */ }
. { printf("UNKNOWN CHARACTER: %c\n", yytext[0]); }
%%

int main(void) {
yylex();
return 0;
}
void yyerror(const char *s)
{fprintf(stderr, "Error: %s\n", s);

}
3
OUTPUT :

RESULT:

Thus the execution of lex program is implemented successfully.


4
EX NO :03
GENERATE YACC SPECIFICATION FOR A FEW SYNTACTIC CATEGORIES
DATE :

AIM:
To write a program to do exercise on syntax analysis using yacc

ALGORITHM:

STEP 1 : Read an expression from the user, allowing for multiple entries until the user decides to
exit.
STEP 2 :Use the lexer to tokenize the input, recognizing operators, identifiers, and numbers.
STEP 3 :Pass the tokens to the parser to construct a syntax tree based on defined grammar rules.
STEP 4 :Perform actions based on the parsed structure and validate the expression.
STEP 5 :Catch and report any syntax or lexical errors during parsing and tokenization

PROGRAM:

Installation - sudo apt-get install bison


Version - yacc --version
Flex file - <file name>.l
Yacc file - <file name>.y
Flex Generate - flex <filename.l>
Yacc Generate - yacc -d <file name.y>
Compilation - gcc lex.yy.c y.tab.c
Run - ./a.out

A) PROGRAM TO RECOGNIZE A VALID ARITHMETIC EXPRESSION THAT USES


OPERATOR +,-,* ,/

LEX CODE: File name .l

%{
#include "y.tab.h"
#include <stdio.h>
#include <stdlib.h>

void yyerror(const char *s);


%}

%%

"=" { printf("\nOperator is EQUAL\n"); return '='; }


"+" { printf("\nOperator is ADDITION\n"); return '+'; }
"-" { printf("\nOperator is SUBTRACTION\n"); return '-'; }
"*" { printf("\nOperator is MULTIPLICATION\n"); return '*'; }
"/" { printf("\nOperator is DIVISION\n"); return '/'; }
[0-9]+ { printf("Number is %s\n", yytext); return NUMBER; }
[a-zA-Z]+[0-9]* {
printf("Identifier is %s\n", yytext);
return ID;

5
}
\n { /* ignore newlines */ }
[ \t]+ { /* ignore whitespace */ }
. { fprintf(stderr, "Unexpected character: %c\n", yytext[0]); exit(1); }

%%

int yywrap() {
return 1;
}

YACC CODE: File name.y

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

void yyerror(const char *s);


%}

%token ID NUMBER

%%

statement:
ID '=' E { printf("\nValid arithmetic expression\n"); }
|E { printf("\nValid arithmetic expression\n"); }
;

E:
E '+' E { printf("Addition\n"); }
| E '-' E { printf("Subtraction\n"); }
| E '*' E { printf("Multiplication\n"); }
| E '/' E { printf("Division\n"); }
| ID { printf("Identifier\n"); }
| NUMBER { printf("Number\n"); }
;

%%

void yyerror(const char *s) {


fprintf(stderr, "Error: %s\n", s);
}

int main() {
printf("Enter an expression:\n");
yyparse();
return 0;
}

6
OUTPUT:

B) PROGRAM TO RECOGNIZE A VALID WHICH STARTS WITH A LETTER FOLLOWED BY


ANY NUMBER OF LETTERS OR DIGITS.

ALGORITHM:

STEP1: The lexer identifies keywords (int, float, double), identifiers, and handles whitespace while
returning appropriate tokens.
STEP2: For identifiers, the lexer prints the recognized identifier name using yytext before returning
the ID token.
STEP3: The parser processes a series of declarations, supporting multiple variable declarations of
the same type with a comma-separated list.
STEP4: Each grammar rule defines how types are associated with identifiers, allowing for complex
declarations like int a, b;.
STEP5: The parser invokes yyerror to report any syntax errors encountered during parsing, aiding in
debugging.

LEX CODE: File name .l

%{
#include "y.tab.h"
#include <stdio.h>
%}

%%
"int" { return INT; }
"float" { return FLOAT; }
"double" { return DOUBLE; }
[a-zA-Z][a-zA-Z0-9]* {
printf("Identifier is %s\n", yytext);
return ID;
}
[ \t]+ ; /* Ignore whitespace */
\n { return '\n'; }
. { return yytext[0]; }
%%

int yywrap() {
return 1;
}
7
YACC CODE: File name.y

%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();
extern char* yytext;
void yyerror(const char *s);
%}

%token ID INT FLOAT DOUBLE

%%
program: declarations
;

declarations: declarations declaration


| declaration
;

declaration: type IDs


;

type: INT
| FLOAT
| DOUBLE
;

IDs: ID
| ID ',' IDs
;

%%

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

void yyerror(const char *s) {


fprintf(stderr, "Error: %s\n", s);
}
OUTPUT:

8
C) PROGRAM TO RECOGNIZE THE GRAMMAR(ABD WHERE N>=10)

ALGORITHM:

STEP1: The lexer recognizes characters a and b, returning tokens A and B, while also passing
through any other characters and newline characters.
STEP2: The lexer processes input until it encounters a newline, preparing tokens for the parser to
analyze the structure of the input string.
STEP3: The parser is defined to expect a sequence of ten A tokens followed by an anb structure,
ensuring that valid strings conform to the format aaaaaaaab.
STEP4: The anb rule allows for recursive construction of sequences, ensuring at least ten A tokens
are present before possibly concluding with a B.
STEP5: The parser utilizes yyerror to print "Invalid string" if the input does not match the expected
format, while successfully matched strings output "Valid string."

LEX CODE: anb.l

%{

#include "y.tab.h"
%}

%%
a { return A; }
b { return B; }
. { return yytext[0]; }
\n { return '\n'; }

%%

int yywrap() { return 1; }

YACC CODE: anb.y

%{
/* YACC program for recognizing anb (n >= 10) */
#include <stdio.h>
%}

%token A B

%%

stmt: A A A A A A A A A A anb '\n' {


printf("\nValid string\n");
}
;

anb: A anb | A B ;

%%

int main() {

9
printf("\nEnter some valid string:\n");
yyparse();
return 0;
}

void yyerror(char *s) {


printf("\nInvalid string\n");
}

OUTPUT:

D) IMPLEMENTATION OF CALCULATOR USING LEX AND YACC

ALGORITHM:

STEP1: The lexer identifies numbers and operators (+, -, *, /, (, )) and returns corresponding tokens,
while ignoring whitespace and handling unrecognized characters with an error message.
STEP2: Tokens for numbers and operators are defined, enabling the parser to recognize and process
arithmetic expressions.
STEP3: The parser's grammar rules support basic arithmetic operations, allowing for addition,
subtraction, multiplication, and division, with proper handling of parentheses.
STEP4: The parser checks for division by zero and invokes an error function to print appropriate
error messages, preventing runtime errors.
STEP5:The main function runs an interactive calculator, continuously parsing user input until an
error occurs or the user exits.

LEX CODE: File name .l

%{
#include "y.tab.h"
#include <stdlib.h>
void yyerror(const char *s);
%}

%%

[0-9]+ { yylval = atoi(yytext); return NUMBER; }


"+" { return PLUS; }
"-" { return MINUS; }
"*" { return MULTIPLY; }
"/" { return DIVIDE; }
10
"(" { return LPAREN; }
")" { return RPAREN; }
[ \t]+ { /* ignore whitespace */ }
\n { return 0; } // Handle new lines
. { yyerror("Unrecognized character"); }

%%

// Define yywrap function


int yywrap() {
return 1;
}

YACC CODE: File name.y

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

void yyerror(const char *s) {


fprintf(stderr, "Error: %s\n", s);
}

int yylex(void); // Declare yylex


%}

%token NUMBER
%token PLUS MINUS MULTIPLY DIVIDE LPAREN RPAREN

%%

// Grammar rules
expr:
expr PLUS expr { printf("Result: %g\n", (double)($1 + $3)); }
| expr MINUS expr { printf("Result: %g\n", (double)($1 - $3)); }
| expr MULTIPLY expr { printf("Result: %g\n", (double)($1 * $3)); }
| expr DIVIDE expr {
if ($3 == 0) {
yyerror("divide by zero");
$$ = 0; // Avoid division by zero
} else {
printf("Result: %g\n", (double)($1 / $3));
}
}
| LPAREN expr RPAREN { $$ = $2; }
| NUMBER { $$ = $1; }
;

%%
int main() {
printf("Simple Calculator:\n");
while (yyparse() == 0); // Loop until an error or EOF
return 0;
}

11
OUTPUT:

RESULT:

Thus the yacc specification for a few syntactic categories program was successfully implemented.

12
EX NO :04
GENERATE THREE ADDRESS CODE FOR A SIMPLE PROGRAM USING
DATE : PROGRAM USING LEX AND YACC

AIM:
To generate three address code for a simple program using LEX and YACC

ALGORITHM:

STEP 1 :The lexer processes input strings to identify tokens using regular expressions.
STEP 2 :The parser uses the defined grammar rules to build a parse tree, processing statements and
expressions based on operator precedence and associativity.
STEP 3 :For each grammar rule, semantic actions are executed to print intermediate results and
build expressions.
STEP 4 : Strings are dynamically allocated using strdup, requiring careful memory management to
prevent leaks.
STEP 5 :The parser invokes yyerror for syntax errors, providing feedback to the user when the input
does not conform to the expected grammar.

PROGRAM :

FLEX CODE: File name.l

%{
#include "y.tab.h"
#include <stdlib.h>
#include <string.h>
%}
%%
[a-z]+ { yylval.sval = strdup(yytext); return IDENT; }
[0-9]+ { yylval.sval = strdup(yytext); return NUM; }
"+" { return PLUS; }
"*" { return MUL; }
"=" { return ASSIGN; }
\n { return EOL; }
%%

YACC CODE: File name.y

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int yylex();
int t = 0;
void yyerror(const char *s) { fprintf(stderr, "Error: %s\n", s); }
%}

%union {
char *sval;
int ival;
13
}

%token <sval> IDENT NUM


%token PLUS MUL ASSIGN EOL

%type <sval> expr term factor

%%

stmt: IDENT ASSIGN expr EOL { printf("%s = %s\n", $1, $3); }


expr: term { $$ = $1; } | expr PLUS term { printf("t%d = %s + %s\n", t++, $1, $3); $$ = strdup("t0"); }
term: factor { $$ = $1; } | term MUL factor { printf("t%d = %s * %s\n", t++, $1, $3); $$ = strdup("t0"); }
factor: IDENT { $$ = $1; } | NUM { $$ = $1; }

%%

int main() { return yyparse(); }

OUTPUT:

RESULT:

Thus the three address code for a simple program using program using lex and yacc has been
executed successfully.

14
EX NO :05 IMPLEMENTATION OF TYPE CHECKING
DATE :

AIM:
To write a c program for implementing of type checking for given expressions

ALGORITHM:

STEP 1:The lexer defines tokens for integers, floats, identifiers, and arithmetic operators, along with
rules for recognizing valid expressions and statements.
STEP 2:The parser processes a program consisting of statements, which include variable type
declarations, variable assignments, and expressions.
STEP 3:It checks for type consistency during assignments by tracking the expected type of variables.
STEP 4:The parsing rules allow for basic arithmetic expressions, ensuring they conform to type
expectations.
STEP 5:Error handling is incorporated to report unexpected characters and type mismatches during
parsing.

PROGRAM:

FLEX CODE: File name.l

%{
#include "parser.tab.h"
%}

%%

int { return INT; }


float { return FLOAT; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
[0-9]+"."[0-9]+ { yylval = atof(yytext); return FNUMBER; }
[a-zA-Z_][a-zA-Z0-9_]* { return IDENTIFIER; } // Variable names (identifiers)
"=" { return ASSIGN; } // Assignment operator
"+" { return PLUS; }
"-" { return MINUS; }
"*" { return MUL; }
"/" { return DIV; }
";" { return SEMI; }
[ \t\n] { /* Ignore whitespaces */ }
. { printf("Unexpected character: %s\n", yytext); }

%%

int yywrap(void) {
return 1;
}

15
YACC CODE: File name.y

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

void yyerror(const char* s);


int yylex(void);

enum { TYPE_INT, TYPE_FLOAT }; // For type checking

int current_type = TYPE_INT;


%}

%token INT FLOAT NUMBER FNUMBER IDENTIFIER


%token PLUS MINUS MUL DIV ASSIGN SEMI

%%

program:
program stmt SEMI
| /* empty */
;

stmt:
type var ASSIGN expr
{
if ($4 == current_type) {
printf("Valid assignment.\n");
} else {
printf("Type error: Mismatched types in assignment.\n");
}
}
;

type:
INT
{
current_type = TYPE_INT;
}
| FLOAT
{
current_type = TYPE_FLOAT;
}
;

var:
IDENTIFIER
{
// You can add variable tracking here
}
;

16
expr:
NUMBER
{
$$ = TYPE_INT;
}
| FNUMBER
{
$$ = TYPE_FLOAT;
}
| expr PLUS expr
| expr MINUS expr
| expr MUL expr
| expr DIV expr
;

%%

void yyerror(const char* s) {


printf("Error: %s\n", s);
}

int main(void) {
return yyparse();
}

OUTPUT:

RESULT:

Thus the type checking was executed successfully .

17
EX NO :06
IMPLEMENTATION OF CODE OPTIMIZATION TECHNIQUE
DATE :

AIM:
To write a program for implementation of code optimization technique.

ALGORITHM:

STEP1: Get the number of operations n and then read each operation’s left-
hand side character L and right-hand side string r into the op array.
STEP2: Check if each L is used in any other operation’s r. If not, mark it as
alive and store it in the pr array.
STEP3: Identify and remove operations with duplicate right-hand side strings
by nullifying their left-hand side characters.
STEP4: Output the optimized operations from the pr array where the left-hand
side character is not null.
STEP5: Complete execution and exit the program.

PROGRAM:

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#define MAX 10
struct op {
char L;
char r[20];
} op[MAX], pr[MAX];
int main() {
int n, z = 0;
printf(&quot;Enter the Number of values: &quot;);
scanf(&quot;%d&quot;, &amp;n);
getchar();

for (int i = 0; i &lt; n; i++) {

printf(&quot;Left: &quot;);
scanf(&quot;%c&quot;, &amp;op[i].L);
printf(&quot;Right: &quot;);
scanf(&quot;%s&quot;, op[i].r);
getchar();
}

for (int i = 0; i &lt; n; i++) {


int is_dead = 0;
for (int j = 0; j &lt; n; j++) {
if (strchr(op[j].r, op[i].L)) {
is_dead = 1;
break;
}
}
18
if (!is_dead) {
pr[z++] = op[i];
}
}

for (int i = 0; i &lt; z; i++) {


for (int j = i + 1; j &lt; z; j++) {
if (strcmp(pr[i].r, pr[j].r) == 0) {
pr[j].L = &#39;\0&#39;;
}
}
}
printf(&quot;OPTIMIZED CODE\n&quot;);
for (int i = 0; i &lt; z; i++) {
if (pr[i].L != &#39;\0&#39;) {
printf(&quot;%c = %s \n&quot;, pr[i].L, pr[i].r);
}
}
return 0;
}

OUTPUT:

RESULT:

Thus the code optimization technique has been successfully executed.

19
EX NO :07
IMPLEMENTATION OF BACKEND OF THE COMPILER
DATE :

AIM:

To develop the Backend of the compiler the target assembly instructions can be simple
move,add,sub,jump also simple addressing modes are used.

ALGORITHM:

STEP1: The program prompts the user to enter intermediate code lines until "exit" is entered,
storing them in a 2D array.
STEP2: It iterates through the stored intermediate code, extracting operations and operands
for each line.
STEP3: A switch statement identifies the operation based on the second character of the string,
mapping it to corresponding assembly-like instructions (ADD, SUB, etc.).
STEP4: For each line of intermediate code, it generates and prints the appropriate target code,
moving operands to registers and performing the identified operation.
STEP5: The output format ensures each operation is correctly structured, reflecting the source
and destination registers.

PROGRAM:

#include <stdio.h>
#include <string.h>
void main() {
char icode[10][30], str[20], opr[10];
int i = 0;
printf("\nEnter intermediate code (terminated by 'exit'):\n");
while (scanf("%s", icode[i]), strcmp(icode[i],"exit") !=0)i++;
printf("\nTarget code generation\n************************");
for (i = 0; i < 10 && strcmp(icode[i], "exit") != 0; i++){
strcpy(str, icode[i]);
switch (str[1]) {
case '+': strcpy(opr, "ADD"); break;
case '-': strcpy(opr, "SUB"); break;
case '*': strcpy(opr, "MUL"); break;
case '/': strcpy(opr, "DIV"); break;
default: strcpy(opr, "UNKNOWN"); break;
}
printf("\n\tMov %c, R%d", str[0], i);
printf("\n\t%s %c, R%d", opr, str[2], i);
printf("\n\tMov R%d, %c", i, str[0]);
}
}

20
OUTPUT:

RESULT:

Thus the Backend of the compiler program was successfully executed.

21

You might also like