CS3501_LABMANUAL
CS3501_LABMANUAL
CS3501_LABMANUAL
Register No :
Staff In-charge H. O .D
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:
PROGRAM:
#include <stdio.h>
#include <ctype.h>
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 :
PROGRAM:
%{
#include <stdio.h>
#include <stdlib.h>
%%
[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:
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:
%{
#include "y.tab.h"
#include <stdio.h>
#include <stdlib.h>
%%
5
}
\n { /* ignore newlines */ }
[ \t]+ { /* ignore whitespace */ }
. { fprintf(stderr, "Unexpected character: %c\n", yytext[0]); exit(1); }
%%
int yywrap() {
return 1;
}
%{
#include <stdio.h>
#include <stdlib.h>
%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"); }
;
%%
int main() {
printf("Enter an expression:\n");
yyparse();
return 0;
}
6
OUTPUT:
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.
%{
#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);
%}
%%
program: declarations
;
type: INT
| FLOAT
| DOUBLE
;
IDs: ID
| ID ',' IDs
;
%%
int main() {
yyparse();
return 0;
}
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."
%{
#include "y.tab.h"
%}
%%
a { return A; }
b { return B; }
. { return yytext[0]; }
\n { return '\n'; }
%%
%{
/* YACC program for recognizing anb (n >= 10) */
#include <stdio.h>
%}
%token A B
%%
anb: A anb | A B ;
%%
int main() {
9
printf("\nEnter some valid string:\n");
yyparse();
return 0;
}
OUTPUT:
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.
%{
#include "y.tab.h"
#include <stdlib.h>
void yyerror(const char *s);
%}
%%
%%
%{
#include <stdio.h>
#include <stdlib.h>
%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 :
%{
#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; }
%%
%{
#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
}
%%
%%
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:
%{
#include "parser.tab.h"
%}
%%
%%
int yywrap(void) {
return 1;
}
15
YACC CODE: File name.y
%{
#include <stdio.h>
#include <stdlib.h>
%%
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
;
%%
int main(void) {
return yyparse();
}
OUTPUT:
RESULT:
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 <stdio.h>
#include <string.h>
#define MAX 10
struct op {
char L;
char r[20];
} op[MAX], pr[MAX];
int main() {
int n, z = 0;
printf("Enter the Number of values: ");
scanf("%d", &n);
getchar();
printf("Left: ");
scanf("%c", &op[i].L);
printf("Right: ");
scanf("%s", op[i].r);
getchar();
}
OUTPUT:
RESULT:
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:
21