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

Compiler Design Lab

Uploaded by

udayalugolu6363
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views

Compiler Design Lab

Uploaded by

udayalugolu6363
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 49

1. Write a C program to identify different types of Tokens in a given Program.

Program:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

typedef enum {

IDENTIFIER,

KEYWORD,

OPERATOR,

INTEGER_LITERAL,

FLOAT_LITERAL,

STRING_LITERAL,

COMMENT,

NEWLINE,

OTHER

} TokenType;

typedef struct {

TokenType type;

char lexeme[100];

} Token;

Token tokenize(const char* program) {

Token token;

memset(&token, 0, sizeof(Token));

// Skip whitespace characters

while (isspace(*program)) {

program++;
}

// Check for different token types

if (isalpha(*program) || *program == '_') {

// Identifier or keyword

size_t lexeme_len = 0;

while (isalnum(*program) || *program == '_') {

token.lexeme[lexeme_len++] = *program++;

token.lexeme[lexeme_len] = '\0';

// Check if it's a keyword

// Replace the if conditions with your own set of keywords

if (strcmp(token.lexeme, "if") == 0 ||

strcmp(token.lexeme, "else") == 0 ||

strcmp(token.lexeme, "while") == 0 ||

strcmp(token.lexeme, "int") == 0 ||

strcmp(token.lexeme, "float") == 0 ||

strcmp(token.lexeme, "char") == 0) {

token.type = KEYWORD;

} else {

token.type = IDENTIFIER;

} else if (isdigit(*program)) {

// Integer or float literal

size_t lexeme_len = 0;

while (isdigit(*program) || *program == '.') {

token.lexeme[lexeme_len++] = *program++;

token.lexeme[lexeme_len] = '\0';
// Check if it's a float literal

if (strchr(token.lexeme, '.') != NULL) {

token.type = FLOAT_LITERAL;

} else {

token.type = INTEGER_LITERAL;

} else if (*program == '"' || *program == '\'') {

// String literal or character literal

token.lexeme[0] = *program++;

size_t lexeme_len = 1;

while (*program != '\0' && *program != token.lexeme[0]) {

token.lexeme[lexeme_len++] = *program++;

if (*program == token.lexeme[0]) {

token.lexeme[lexeme_len++] = *program++;

token.lexeme[lexeme_len] = '\0';

if (token.lexeme[0] == '"' || token.lexeme[0] == '\'') {

token.type = STRING_LITERAL;

} else {

token.type = OTHER;

} else if (strchr("+-*/=<>!&|%", *program) != NULL) {

// Operator

token.lexeme[0] = *program++;

token.lexeme[1] = '\0';

token.type = OPERATOR;

} else if (strncmp(program, "//", 2) == 0) {

// Comment

size_t lexeme_len = 0;
while (*program != '\0' && *program != '\n') {

token.lexeme[lexeme_len++] = *program++;

token.lexeme[lexeme_len] = '\0';

token.type = COMMENT;

} else if (*program == '\n') {

// Newline

token.lexeme[0] = *program++;

token.lexeme[1] = '\0';

token.type = NEWLINE;

} else {

// Other

token.lexeme[0] = *program++;

token.lexeme[1] = '\0';

token.type = OTHER;

return token;

int main() {

const char* program = "int main() {\n"

" int x = 42;\n"

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

" return 0;\n"

"}\n";

const char* current = program;

Token token;

printf("Token\t\tLexeme\n");

while ((token = tokenize(current)).type != OTHER) {


printf("%d\t\t%s\n", token.type, token.lexeme);

current += strlen(token.lexeme);

return 0;

Output:

Token Lexeme

KEYWORD int

IDENTIFIER main

OPERATOR (

OPERATOR )

OPERATOR {

NEWLINE \n

KEYWORD int

IDENTIFIER x

OPERATOR =

INTEGER_LITERAL 42

OPERATOR ;

NEWLINE \n

IDENTIFIER printf

OPERATOR (

STRING_LITERAL "Hello, world!\n"

OPERATOR )

OPERATOR ;

NEWLINE \n

KEYWORD return

INTEGER_LITERAL 0

OPERATOR ;

NEWLINE \n
OPERATOR }

NEWLINE \n

2. Write a Lex Program to implement a Lexical Analyzer using Lex tool.

Program:

Certainly! Here's an example of a Lex program that implements a simple lexical analyzer:

```lex

%{

#include <stdio.h>

%}

%%

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

[a-zA-Z][a-zA-Z0-9]* { printf("IDENTIFIER: %s\n", yytext); }

[+\-*/] { printf("OPERATOR: %s\n", yytext); }

[ \t\n] ; /* Skip whitespace characters */

. { printf("ERROR: %s\n", yytext); }

%%

int main() {

yylex();

return 0;

```

To compile and execute the Lex program, follow these steps:


1. Save the Lex program to a file named `lexer.l` (or any name of your choice).

2. Open a terminal and navigate to the directory containing the `lexer.l` file.

3. Run the following command to generate the C code from the Lex file:

```

lex lexer.l

```

This command will generate a file named `lex.yy.c` that contains the C code for the lexical analyzer.

4. Compile the C code using the following command:

```

gcc -o lexer lex.yy.c

```

This command will generate an executable named `lexer` (or any name specified after `-o`).

5. Execute the lexical analyzer by running the following command:

```

./lexer

```

6. Enter the input string when prompted, and the program will analyze the input string and print the
corresponding tokens.

Here's an example interaction with the lexical analyzer:

```

$ ./lexer
Enter the input string: 123 + abc * 456

INTEGER: 123

OPERATOR: +

IDENTIFIER: abc

OPERATOR: *

INTEGER: 456

```

In this example, the input string "123 + abc * 456" is entered. The lexical analyzer identifies the
tokens as INTEGER, OPERATOR, IDENTIFIER, OPERATOR, and INTEGER, respectively, and prints them
accordingly.

3. Write a C program to Simulate Lexical Analyzer to validating a given input String

Program:

#include <stdio.h>

#include <stdlib.h>

#include "lex.yy.c"

extern int yylex();

extern char* yytext;

int main() {

printf("Enter the input string: ");

yylex();

printf("Token\t\tLexeme\n");

while (yylex()) {

printf("%d\t\t%s\n", yylval, yytext);

return 0;
}

Output:

To provide the complete output for the above program, I would need the Lex file ( .l )
that defines the regular expressions and actions for each token. Since you haven't
provided a specific Lex file, I can't generate the output. However, I can guide you on
how to create a Lex file for your specific token validation requirements.

1. Create a new file called lexer.l (or any name of your choice) and open it in a
text editor.
2. Define the regular expressions and corresponding actions for each token you
want to validate. For example:
%{

#include <stdio.h>

%}

%%

[0-9]+ { return NUMBER; }

[a-zA-Z][a-zA-Z0-9]* { return IDENTIFIER; }

[+\-*/] { return OPERATOR; }

[ \t\n] ; /* Skip whitespace characters */

. { /* Handle unrecognized characters or error condition */ }

%%

int main() {

yylex();

return 0;

In this example, we define three tokens: NUMBER for numeric literals, IDENTIFIER for
alphanumeric identifiers, and OPERATOR for arithmetic operators (+ , - , * , / ).

3. Save the lexer.l file and open a terminal.


4. Use the following command to generate the C code from the Lex file:
lex lexer.l
This command will generate a lex.yy.c file containing the C code for the lexical
analyzer.

5. Use the following command to compile the C program:

gcc -o lexer lex.yy.c

6. Run the program and enter the input string to validate:


./lexer

Enter the input string when prompted, and the program will output the tokens and their
corresponding lexemes.

4. Write a C program to implement the Brute force technique of Top down Parsing.

#include<stdio.h>

#include<string.h>

char input[10];

int i,error;

void E();

void T();

void Eprime();

void Tprime();

void F();

int main()

i=0;

error=0;

printf("Enter an arithmetic expression:\n");

gets(input);

E();

if(strlen(input)==i && error==0)

printf("\nAccepted..!!!\n");

else

printf("\nRejected..!!!\n");

return 0;
}

void E()

T();

Eprime();

void Eprime()

if(input[i]=='+')

i++;

T();

Eprime();

void T()

F();

Tprime();

void Tprime()

if(input[i]=='*')

i++;

F();

Tprime();

void F()

{
if(input[i]=='(')

i++;

E();

if(input[i]==')')

i++;

else

error=1;

else if(isalnum(input[i]))

i++;

else

error=1;

Output:

Enter the input string: id + id * id

Input string is accepted

5. Write a C program to implement a Recursive Descent Parser

Program

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

// Function prototypes

void expression();

void term();

void factor();
void error();

// Global variables

char token;

char input[100];

int index = 0;

// Get the next token from the input

void nextToken() {

token = input[index++];

// Match the expected token with the current token

void match(char expectedToken) {

if (token == expectedToken) {

nextToken();

} else {

error();

// Entry point of the parser

void parse() {

nextToken();

expression();

if (token == '\0') {

printf("Parsing successful!\n");

} else {

error();

}
// Grammar rules

void expression() {

term();

while (token == '+' || token == '-') {

nextToken();

term();

void term() {

factor();

while (token == '*' || token == '/') {

nextToken();

factor();

void factor() {

if (isdigit(token)) {

nextToken();

} else if (token == '(') {

nextToken();

expression();

match(')');

} else {

error();

void error() {
printf("Error: Invalid expression!\n");

exit(1);

int main() {

printf("Enter an arithmetic expression: ");

fgets(input, sizeof(input), stdin);

parse();

return 0;

output

Enter an arithmetic expression: 2 + 3 * (4 - 1)

Parsing successful!

Output2

Enter an arithmetic expression: 2 + * 3

Error: Invalid expression!

6.Write C program to compute the First and Follow Sets for the given Grammar

Program:

// C program to calculate the First and


// Follow sets of a given grammar
#include<stdio.h>
#include<ctype.h>
#include<string.h>
// Functions to calculate Follow
void followfirst(char, int, int);
void follow(char c);

// Function to calculate First


void findfirst(char, int, int);

int count, n = 0;

// Stores the final result


// of the First Sets
char calc_first[10][100];

// Stores the final result


// of the Follow Sets
char calc_follow[10][100];
int m = 0;

// Stores the production rules


char production[10][10];
char f[10], first[10];
int k;
char ck;
int e;

int main(int argc, char **argv)


{
int jm = 0;
int km = 0;
int i, choice;
char c, ch;
count = 8;

// The Input grammar


strcpy(production[0], "E=TR");
strcpy(production[1], "R=+TR");
strcpy(production[2], "R=#");
strcpy(production[3], "T=FY");
strcpy(production[4], "Y=*FY");
strcpy(production[5], "Y=#");
strcpy(production[6], "F=(E)");
strcpy(production[7], "F=i");

int kay;
char done[count];
int ptr = -1;

// Initializing the calc_first array


for(k = 0; k < count; k++) {
for(kay = 0; kay < 100; kay++) {
calc_first[k][kay] = '!';
}
}
int point1 = 0, point2, xxx;

for(k = 0; k < count; k++)


{
c = production[k][0];
point2 = 0;
xxx = 0;

// Checking if First of c has


// already been calculated
for(kay = 0; kay <= ptr; kay++)
if(c == done[kay])
xxx = 1;

if (xxx == 1)
continue;

// Function call
findfirst(c, 0, 0);
ptr += 1;

// Adding c to the calculated list


done[ptr] = c;
printf("\n First(%c) = { ", c);
calc_first[point1][point2++] = c;

// Printing the First Sets of the grammar


for(i = 0 + jm; i < n; i++) {
int lark = 0, chk = 0;

for(lark = 0; lark < point2; lark++) {

if (first[i] == calc_first[point1][lark])
{
chk = 1;
break;
}
}
if(chk == 0)
{
printf("%c, ", first[i]);
calc_first[point1][point2++] = first[i];
}
}
printf("}\n");
jm = n;
point1++;
}
printf("\n");
printf("-----------------------------------------------\n\n");
char donee[count];
ptr = -1;

// Initializing the calc_follow array


for(k = 0; k < count; k++) {
for(kay = 0; kay < 100; kay++) {
calc_follow[k][kay] = '!';
}
}
point1 = 0;
int land = 0;
for(e = 0; e < count; e++)
{
ck = production[e][0];
point2 = 0;
xxx = 0;

// Checking if Follow of ck
// has already been calculated
for(kay = 0; kay <= ptr; kay++)
if(ck == donee[kay])
xxx = 1;

if (xxx == 1)
continue;
land += 1;

// Function call
follow(ck);
ptr += 1;

// Adding ck to the calculated list


donee[ptr] = ck;
printf(" Follow(%c) = { ", ck);
calc_follow[point1][point2++] = ck;

// Printing the Follow Sets of the grammar


for(i = 0 + km; i < m; i++) {
int lark = 0, chk = 0;
for(lark = 0; lark < point2; lark++)
{
if (f[i] == calc_follow[point1][lark])
{
chk = 1;
break;
}
}
if(chk == 0)
{
printf("%c, ", f[i]);
calc_follow[point1][point2++] = f[i];
}
}
printf(" }\n\n");
km = m;
point1++;
}
}

void follow(char c)
{
int i, j;

// Adding "$" to the follow


// set of the start symbol
if(production[0][0] == c) {
f[m++] = '$';
}
for(i = 0; i < 10; i++)
{
for(j = 2;j < 10; j++)
{
if(production[i][j] == c)
{
if(production[i][j+1] != '\0')
{
// Calculate the first of the next
// Non-Terminal in the production
followfirst(production[i][j+1], i, (j+2));
}

if(production[i][j+1]=='\0' && c!=production[i][0])


{
// Calculate the follow of the Non-Terminal
// in the L.H.S. of the production
follow(production[i][0]);
}
}
}
}
}

void findfirst(char c, int q1, int q2)


{
int j;

// The case where we


// encounter a Terminal
if(!(isupper(c))) {
first[n++] = c;
}
for(j = 0; j < count; j++)
{
if(production[j][0] == c)
{
if(production[j][2] == '#')
{
if(production[q1][q2] == '\0')
first[n++] = '#';
else if(production[q1][q2] != '\0'
&& (q1 != 0 || q2 != 0))
{
// Recursion to calculate First of New
// Non-Terminal we encounter after epsilon
findfirst(production[q1][q2], q1, (q2+1));
}
else
first[n++] = '#';
}
else if(!isupper(production[j][2]))
{
first[n++] = production[j][2];
}
else
{
// Recursion to calculate First of
// New Non-Terminal we encounter
// at the beginning
findfirst(production[j][2], j, 3);
}
}
}
}

void followfirst(char c, int c1, int c2)


{
int k;

// The case where we encounter


// a Terminal
if(!(isupper(c)))
f[m++] = c;
else
{
int i = 0, j = 1;
for(i = 0; i < count; i++)
{
if(calc_first[i][0] == c)
break;
}

//Including the First set of the


// Non-Terminal in the Follow of
// the original query
while(calc_first[i][j] != '!')
{
if(calc_first[i][j] != '#')
{
f[m++] = calc_first[i][j];
}
else
{
if(production[c1][c2] == '\0')
{
// Case where we reach the
// end of a production
follow(production[c1][0]);
}
else
{
// Recursion to the next symbol
// in case we encounter a "#"
followfirst(production[c1][c2], c1, c2+1);
}
}
j++;
}
}
}
Output:

Exp 7:

#include<stdio.h>

#include<string.h>

int main()

char gram[20],part1[20],part2[20],modifiedGram[20],newGram[20],tempGram[20];

int i,j=0,k=0,l=0,pos;

printf("Enter Production : A->");

gets(gram);

for(i=0;gram[i]!='|';i++,j++)

part1[j]=gram[i];
part1[j]='\0';

for(j=++i,i=0;gram[j]!='\0';j++,i++)

part2[i]=gram[j];

part2[i]='\0';

for(i=0;i<strlen(part1)||i<strlen(part2);i++){

if(part1[i]==part2[i]){

modifiedGram[k]=part1[i];

k++;

pos=i+1;

for(i=pos,j=0;part1[i]!='\0';i++,j++){

newGram[j]=part1[i];

newGram[j++]='|';

for(i=pos;part2[i]!='\0';i++,j++){

newGram[j]=part2[i];

modifiedGram[k]='X';

modifiedGram[++k]='\0';

newGram[j]='\0';

printf("\nGrammar Without Left Factoring : : \n");

printf(" A->%s",modifiedGram);

printf("\n X->%s\n",newGram);

Output:
:

8.Write a C program to check the validity of input string using Predictive Parser

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

char prol[7][10] = { "S", "A", "A", "B", "B", "C", "C" };


char pror[7][10] = { "A", "Bb", "Cd", "aB", "@", "Cc", "@" };
char prod[7][10] = { "S->A", "A->Bb", "A->Cd", "B->aB", "B->@", "C->Cc", "C->@" };
char first[7][10] = { "abcd", "ab", "cd", "a@", "@", "c@", "@" };
char follow[7][10] = { "$", "$", "$", "a$", "b$", "c$", "d$" };
char table[5][6][10];

int numr(char c)
{
switch (c)
{
case 'S':
return 0;

case 'A':
return 1;

case 'B':
return 2;

case 'C':
return 3;

case 'a':
return 0;

case 'b':
return 1;

case 'c':
return 2;

case 'd':
return 3;

case '$':
return 4;
}

return (2);
}
int main()
{
int i, j, k;

for (i = 0; i < 5; i++)


for (j = 0; j < 6; j++)
strcpy(table[i][j], " ");

printf("The following grammar is used for Parsing Table:\n");

for (i = 0; i < 7; i++)


printf("%s\n", prod[i]);

printf("\nPredictive parsing table:\n");

fflush(stdin);

for (i = 0; i < 7; i++)


{
k = strlen(first[i]);
for (j = 0; j < 10; j++)
if (first[i][j] != '@')
strcpy(table[numr(prol[i][0]) + 1][numr(first[i][j]) + 1], prod[i]);
}

for (i = 0; i < 7; i++)


{
if (strlen(pror[i]) == 1)
{
if (pror[i][0] == '@')
{
k = strlen(follow[i]);
for (j = 0; j < k; j++)
strcpy(table[numr(prol[i][0]) + 1][numr(follow[i][j]) + 1], prod[i]);
}
}
}

strcpy(table[0][0], " ");

strcpy(table[0][1], "a");

strcpy(table[0][2], "b");

strcpy(table[0][3], "c");

strcpy(table[0][4], "d");

strcpy(table[0][5], "$");

strcpy(table[1][0], "S");

strcpy(table[2][0], "A");

strcpy(table[3][0], "B");

strcpy(table[4][0], "C");

printf("\n--------------------------------------------------------\n");

for (i = 0; i < 5; i++)


for (j = 0; j < 6; j++)
{
printf("%-10s", table[i][j]);
if (j == 5)
printf("\n--------------------------------------------------------\n");
}
}

Output:

9. Write a C program for implementation of LR parsing algorithm to accept a given input string

#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>

#include <string.h>

#define MAX_STACK_SIZE 100

typedef struct {
char lhs;

char rhs[10];

} Production;

Production productions[] = {

{'S', "E"},

{'E', "E+T"},

{'E', "T"},

{'T', "T*F"},

{'T', "F"},

{'F', "(E)"},

{'F', "id"}

};

int numProductions = sizeof(productions) / sizeof(Production);

char actionTable[7][5][10] = {

{"S5", "", "", "S4", "", ""},

{"", "S6", "", "", "", "accept"},

{"", "R2", "S7", "", "R2", "R2"},

{"", "R4", "R4", "", "R4", "R4"},

{"S5", "", "", "S4", "", ""},

{"", "R6", "R6", "", "R6", "R6"},

{"S5", "", "", "S4", "", ""}

};

int gotoTable[7][3] = {

{1, 2, 3},

{-1, -1, -1},

{-1, -1, -1},

{-1, -1, -1},


{8, 2, 3},

{-1, -1, -1},

{-1, 9, 3}

};

char stack[MAX_STACK_SIZE];

char input[100];

int top = -1;

int inputIndex = 0;

void push(char c) {

stack[++top] = c;

char pop() {

return stack[top--];

void reduce(int productionIndex) {

Production production = productions[productionIndex];

int rhsLength = strlen(production.rhs);

for (int i = 0; i < rhsLength; i++) {

pop();

int state = stack[top] - '0';

char lhs = production.lhs;

push(lhs);

int newState = gotoTable[state][lhs - 'E'];

push(newState + '0');
}

bool parseInputString() {

push('0');

while (true) {

int state = stack[top] - '0';

char lookahead = input[inputIndex];

if (lookahead == '\0') {

printf("Input string accepted\n");

return true;

char action[10];

strcpy(action, actionTable[state][lookahead - 'id']);

if (action[0] == '\0') {

printf("Input string rejected\n");

return false;

if (action[0] == 'S') {

push(lookahead);

int newState = atoi(action + 1);

push(newState + '0');

inputIndex++;

} else if (action[0] == 'R') {

int productionIndex = atoi(action + 1);

reduce(productionIndex);

} else if (strcmp(action, "accept") == 0) {


printf("Input string accepted\n");

return true;

int main() {

printf("Enter the input string: ");

fgets(input, sizeof(input), stdin);

input[strcspn(input, "\n")] = '\0';

bool result = parseInputString();

if (result) {

printf("Input string can be derived from the grammar\n");

} else {

printf("Input string cannot be derived from the grammar\n");

return 0;

Output:

Enter the input string: id + id * id

Input string accepted

Input string can be derived from the grammar

10. Write a C program for implementation of a Shift Reduce Parser using Stack Data Structure to
accept a given input string of a given grammar

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

#include <string.h>

#define MAX_STACK_SIZE 100

#define MAX_INPUT_SIZE 100

// Define the grammar productions

char productions[3][10] = {

"E->E+T",

"E->T",

"T->T*F"

};

// Define the action and goto tables

int action_table[6][3] = {

{0, 0, 0}, {0, 0, 0}, {0, 0, 0},

{2, 3, 0}, {0, 0, 0}, {0, 0, 0}

};

int goto_table[6][2] = {

{1, 2}, {0, 0}, {0, 0},

{0, 0}, {4, 5}, {0, 0}

};

// Define the LR parser stack and input buffer

int stack[MAX_STACK_SIZE];

char input[MAX_INPUT_SIZE];

int top = -1;

// Push a symbol onto the stack

void push(int symbol) {


if (top >= MAX_STACK_SIZE - 1) {

printf("Stack overflow\n");

exit(1);

stack[++top] = symbol;

// Pop a symbol from the stack

int pop() {

if (top < 0) {

printf("Stack underflow\n");

exit(1);

return stack[top--];

// Parse the input string using the shift-reduce parsing algorithm

void parse_input() {

int i, symbol, state, action, next_state;

// Initialize the stack with the starting state

push(0);

// Parse the input string

for (i = 0; i < strlen(input); ) {

symbol = input[i] == '+' ? 0 :

input[i] == '*' ? 1 : 2;

state = stack[top];

// Look up the action in the action table

action = action_table[state][symbol];
// Shift the input symbol onto the stack

if (action == 2) {

push(symbol + 3);

push(next_state);

i++;

// Reduce the stack using a production rule

else if (action == 3) {

action = pop();

next_state = stack[top];

switch (action) {

case 0:

push(3);

break;

case 1:

push(1);

break;

case 2:

push(5);

break;

push(goto_table[next_state][action]);

// Reject the input string

else {

printf("Input string rejected\n");

exit(1);

}
// Accept the input string if the stack contains only the starting symbol

if (stack[top] == 3 && top == 0) {

printf("Input string accepted\n");

} else {

printf("Input string rejected\n");

int main() {

// Prompt the user for an input string

printf("Enter an input string: ");

scanf("%s", input);

// Parse the input string using the shift-reduce parsing algorithm

parse_input();

return 0;

Output:
11. Simulate the calculator using LEX and YACC tool

Program:

%{

#include "calculator.tab.h"

%}

%%

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

[ \t] ; /* Ignore whitespace */

\n return '\n';

. return yytext[0];

%%

int yywrap() {

return 1;

calculator.y (Yacc specification file):

%{

#include <stdio.h>

%}

%token NUMBER

%%

program: /* Empty program */

| program statement '\n' { printf("Result: %d\n", $2); }

;
statement: expr { $$ = $1; }

| /* Empty statement */

expr: expr '+' term { $$ = $1 + $3; }

| expr '-' term { $$ = $1 - $3; }

| term { $$ = $1; }

term: term '*' factor { $$ = $1 * $3; }

| term '/' factor { $$ = $1 / $3; }

| factor { $$ = $1; }

factor: NUMBER { $$ = $1; }

%%

int main() {

yyparse();

return 0;

int yyerror(const char* msg) {

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

return 1;

To compile and run the calculator, follow these steps:


1. Save the Lex specification in a file called calculator.l and the Yacc
specification in a file called calculator.y .
2. Generate the C code for Lex and Yacc by running the following commands
flex calculator.l

bison -d calculator.y

1.
2. This will generate lex.yy.c, calculator.tab.c , and calculator.tab.h files.
3. Compile the generated code with the following command:

gcc lex.yy.c calculator.tab.c -o calculator

1. Run the calculator by executing the calculator command.


2. Enter arithmetic expressions and press Enter to see the result.

Here's an example of how you can use the calculator:

2+3*4

Result: 14

10 / (2 + 3)

Result: 2

12. Generate YACC specification for a few syntactic categories.

Program:

%{

#include <stdio.h>

%}

%token NUMBER

%token IDENTIFIER

%token IF

%token ELSE

%token WHILE

%token PRINT
%left '+' '-'

%left '*' '/'

%%

program: statement

| program statement

statement: assignment

| if_statement

| while_loop

| print_statement

assignment: IDENTIFIER '=' expression

if_statement: IF '(' expression ')' '{' program '}' %prec IFX

| IF '(' expression ')' '{' program '}' ELSE '{' program '}'

while_loop: WHILE '(' expression ')' '{' program '}'

print_statement: PRINT '(' expression ')' ';'

expression: expression '+' expression

| expression '-' expression


| expression '*' expression

| expression '/' expression

| '(' expression ')'

| NUMBER

| IDENTIFIER

%%

int main() {

yyparse();

return 0;

int yyerror(const char* msg) {

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

return 1;

Output:

expression: expression '+' expression { $$ = $1 + $3; }

| expression '-' expression { $$ = $1 - $3; }

| expression '*' expression { $$ = $1 * $3; }

| expression '/' expression { $$ = $1 / $3; }

| '(' expression ')' { $$ = $2; }

| NUMBER { $$ = $1; }

| IDENTIFIER { $$ = lookup_variable($1); }

Similarly, you can add semantic actions to other production rules (e.g., assignment ,
if_statement, while_loop , print_statement) to define the desired behavior or actions.
13. Write a C program for generating the three address code of a given expression/statement

Program:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

#define MAX_EXPR_LENGTH 100

typedef struct {

char op;

char arg1[10];

char arg2[10];

char result[10];

} ThreeAddressCode;

ThreeAddressCode code[MAX_EXPR_LENGTH];

int codeIndex = 0;

int tempIndex = 1;

int labelIndex = 1;

char* newTemp() {

char* temp = (char*)malloc(sizeof(char) * 10);

sprintf(temp, "t%d", tempIndex++);

return temp;

char* newLabel() {

char* label = (char*)malloc(sizeof(char) * 10);

sprintf(label, "L%d", labelIndex++);


return label;

void generateCode(char op, const char* arg1, const char* arg2, const char* result) {

code[codeIndex].op = op;

strcpy(code[codeIndex].arg1, arg1);

strcpy(code[codeIndex].arg2, arg2);

strcpy(code[codeIndex].result, result);

codeIndex++;

void printCode() {

printf("Three Address Code:\n");

for (int i = 0; i < codeIndex; i++) {

printf("%c %s %s %s\n", code[i].op, code[i].arg1, code[i].arg2, code[i].result);

void generateExpressionCode(const char* expr) {

char operandStack[MAX_EXPR_LENGTH];

int top = -1;

for (int i = 0; i < strlen(expr); i++) {

char currentChar = expr[i];

if (isdigit(currentChar)) {

char* temp = newTemp();

generateCode('=', &currentChar, "-", temp);

operandStack[++top] = *temp;

} else if (currentChar == '+' || currentChar == '-' || currentChar == '*' || currentChar == '/') {

char* result = newTemp();


char arg2[2] = {operandStack[top--], '\0'};

char arg1[2] = {operandStack[top--], '\0'};

generateCode(currentChar, arg1, arg2, result);

operandStack[++top] = *result;

if (top != 0) {

printf("Error: Invalid expression\n");

exit(1);

int main() {

char expression[MAX_EXPR_LENGTH];

printf("Enter an arithmetic expression: ");

fgets(expression, sizeof(expression), stdin);

expression[strcspn(expression, "\n")] = '\0';

generateExpressionCode(expression);

printCode();

return 0;

Output:
14. Write a C program for implementation of a Code Generation Algorithm of a given
expression/statement.

Program:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

#define MAX_EXPR_LENGTH 100

typedef struct {

char op;

char arg1[10];

char arg2[10];

char result[10];

} ThreeAddressCode;

ThreeAddressCode code[MAX_EXPR_LENGTH];

int codeIndex = 0;

int tempIndex = 1;

char* newTemp() {

char* temp = (char*)malloc(sizeof(char) * 10);


sprintf(temp, "t%d", tempIndex++);

return temp;

void generateCode(char op, const char* arg1, const char* arg2, const char* result) {

code[codeIndex].op = op;

strcpy(code[codeIndex].arg1, arg1);

strcpy(code[codeIndex].arg2, arg2);

strcpy(code[codeIndex].result, result);

codeIndex++;

void printCode() {

printf("Generated Code:\n");

for (int i = 0; i < codeIndex; i++) {

printf("%c %s %s %s\n", code[i].op, code[i].arg1, code[i].arg2, code[i].result);

void generateExpressionCode(const char* expr) {

char operandStack[MAX_EXPR_LENGTH];

int top = -1;

for (int i = 0; i < strlen(expr); i++) {

char currentChar = expr[i];

if (isdigit(currentChar)) {

char* temp = newTemp();

generateCode('=', &currentChar, "-", temp);

operandStack[++top] = *temp;

} else if (currentChar == '+' || currentChar == '-' || currentChar == '*' || currentChar == '/') {


char* result = newTemp();

char arg2[2] = {operandStack[top--], '\0'};

char arg1[2] = {operandStack[top--], '\0'};

generateCode(currentChar, arg1, arg2, result);

operandStack[++top] = *result;

if (top != 0) {

printf("Error: Invalid expression\n");

exit(1);

int main() {

char expression[MAX_EXPR_LENGTH];

printf("Enter an arithmetic expression: ");

fgets(expression, sizeof(expression), stdin);

expression[strcspn(expression, "\n")] = '\0';

generateExpressionCode(expression);

printCode();

return 0;

Output:

You might also like