0% found this document useful (0 votes)
7 views33 pages

Trail DC

The document outlines various programming tasks involving language recognition and symbol table implementation using C and LEX. It includes code snippets for recognizing strings with specific patterns, counting characters, words, and lines in a file, and implementing a symbol table for expressions. Additionally, it covers the recognition of floating-point numbers and strings with specific digit arrangements.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views33 pages

Trail DC

The document outlines various programming tasks involving language recognition and symbol table implementation using C and LEX. It includes code snippets for recognizing strings with specific patterns, counting characters, words, and lines in a file, and implementing a symbol table for expressions. Additionally, it covers the recognition of floating-point numbers and strings with specific digit arrangements.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 33

Week -1

1. Implementation of Language recognizer


a. Set of all strings over the binary alphabet containing an even number of a’s and
an even number of b’s. Set of all strings over the binary alphabet containing an
even number of a’s and an even number of b’s.

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

int main() {
char alpha[2];
char input_string[100];

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


printf("Enter alphabet %d: ", i + 1);
scanf(" %c", &alpha[i]);
}

printf("Enter String: ");


scanf(" %s", input_string);

int len_alpha = strlen(alpha);


int len_string = strlen(input_string);

char unique_alpha[2];
int unique_count = 0;

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


int is_unique = 1;
for (int j = 0; j < unique_count; j++) {
if (alpha[i] == unique_alpha[j]) {
is_unique = 0;
break;
}
}
if (is_unique) {
unique_alpha[unique_count++] = alpha[i];
}
}

if (unique_count < 2) {
printf("Invalid String\n");
return 0;
}

int count_alpha1 = 0;
int count_alpha2 = 0;

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


if (unique_alpha[0] == input_string[i]) {
count_alpha1++;
}
if (unique_alpha[1] == input_string[i]) {
count_alpha2++;
}
}
if (count_alpha1 % 2 == 0 && count_alpha2 % 2 == 0) {
printf("Even number of %c's and Even number of %c's\n", unique_alpha[0],
unique_alpha[1]);
printf("Accepted\n");
} else if (count_alpha1 % 2 == 0 && count_alpha2 % 2 != 0) {
printf("Even number of %c's and odd number of %c's\n", unique_alpha[0],
unique_alpha[1]);
printf("Rejected\n");
} else if (count_alpha1 % 2 != 0 && count_alpha2 % 2 == 0) {
printf("Odd number of %c's and Even number of %c's\n", unique_alpha[0],
unique_alpha[1]);
printf("Rejected\n");
} else {
printf("Odd number of %c's and Odd number of %c's\n", unique_alpha[0],
unique_alpha[1]);
printf("Rejected\n");
}

return 0;
}

b. Set of all strings ending with two symbols of the same type.
CODE:-
#include <stdio.h>
#include <string.h>

int main() {
char a[100]; // Assuming a maximum length of 100 characters for the input
string
printf("Enter String: ");
scanf("%s", a);

char l_a[] = {'a', 'b'};


int len_a = sizeof(l_a) / sizeof(l_a[0]);

char l_Str[100]; // Assuming a maximum length of 100 characters for the set
int len_Str;

// Create a set from the input string


int i, j;
len_Str = 0;
for (i = 0; i < strlen(a); i++) {
int is_unique = 1;
for (j = 0; j < len_Str; j++) {
if (l_Str[j] == a[i]) {
is_unique = 0;
break;
}
}
if (is_unique) {
l_Str[len_Str++] = a[i];
}
}

// Check if l_a is a subset of l_Str


int is_subset = 1;
for (i = 0; i < len_a; i++) {
int found = 0;
for (j = 0; j < len_Str; j++) {
if (l_a[i] == l_Str[j]) {
found = 1;
break;
}
}
if (!found) {
is_subset = 0;
break;
}
}

// Check the last two characters of the input string


if (is_subset) {
if (a[strlen(a) - 1] == a[strlen(a) - 2]) {
printf("Accepted\n");
} else {
printf("Rejected\n");
}
} else {
printf("Invalid String\n");
}

return 0;
}

Week-2

1) Write a C Program to implement the Symbol table for the given


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

int main() {
char expression[100];
printf("Enter Expression: ");
scanf("%s", expression);

printf("\t\t\t\tSymbol Table\n");
printf("%-10s %-10s %-10s\n", "Symbol", "Address", "Type");

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


char currentSymbol = expression[i];
char type[20];

if ((currentSymbol >= 'a' && currentSymbol <= 'z') || (currentSymbol >= 'A'
&& currentSymbol <= 'Z')) {
strcpy(type, "identifier");
} else if (currentSymbol == '+' || currentSymbol == '-' || currentSymbol ==
'*' || currentSymbol == '/' || currentSymbol == '%') {
strcpy(type, "operator");
} else {
strcpy(type, "unknown");
}

printf("%-10c %-10p %-10s\n", currentSymbol, (void *)&expression[i], type);


}

return 0;
}

Implement the following programs using LEX tool


a. Identification of Vowels and Consonants
b. count number of vowels and consonants
c. Count the number of Lines in given input
d. Recognize strings ending with 00
e. Recognize a string with three consecutive 0’s

A) Identification of Vowels and Consonants


%{
#include<stdio.h>
int c=0;
%}

%%
[aeiouAEIOU] { printf("It is vowel ",yytext); }
. { printf("It is Consonant ",yytext); }
%%

int yywrap(){
return 1;
}

int main()
{
printf("Enter String: ");
yylex();
getch();
return 0;
}

B) count number of vowels and consonants


%{
#include <stdio.h>
int count = 0;
int count1 = 0;
%}

%%
[aeiouAEIOU] { count++; }
[A-Za-z] { count1++; }
\n { printf("The vowels are : %d\nThe Consonants are :%d\n",count,count1); }
%%

int yywrap() {
return 1;
}
int main() {
printf("Enter a string: ");
yylex();
return 0;

C) Count the number of Lines in given input


%{
#include <stdio.h>
int line_count = 0;
%}

%%
\n { line_count++; }
.|\n
%%

int yywrap() {
return 1;
}

int main() {
printf("Enter input (Ctrl+Z followed by Enter to end):\n");
yylex();
printf("The line count is %d",line_count);
getch();
return 0;
}

D)Recognize strings ending with 00


%{
#include<stdio.h>
int c=0;
%}

%%
.*00$ c=1;
. c=0;
%%

int yywrap(void)
{
return 1;
}

int main()
{ printf("Enter a string:");
yylex();
if(c==1)
printf("Accepted");
else
printf("Not Accepted");
getch();
return 0;
}
E) Recognize a string with three consecutive 0’s
%{
#include <stdio.h>
int c = 0;
%}

%%
.*000 { c=1; }
. { c=0; }
%%

int yywrap() {
return 1;
}

int main() {
printf("Enter the String: ");
yylex();
if (c == 1)
printf("Accepted\n");
else
printf("Not Accepted\n");
getch(); return 0;
}

WEEK-3

Write a LEX program to recognize the following tokens over the


alphabets {0,1,..,9}
a) The set of all string ending in 00.
%{
#include<stdio.h>
int c=0;
%}

%%
[0-9]00 c=1;
. c=0;
%%

int yywrap(void)
{
return 1;
}

int main()
{ printf("Enter a string:");
yylex();
if(c==1)
printf("Accepted");
else
printf("Not Accepted");
getch();
return 0;
}
B) The set of all strings with three consecutive 222’s.
%{
#include<stdio.h>
int c=0;
%}

%%
([0-9]*222[0-9]*)+ { c=1; }
. {c=0; }
%%

int yywrap(){
return 1;
}

int main(){
printf("Enter String");
yylex();
if(c==1)
printf("Accepted");
else
printf("Not accepted");

getch();
return 0;
}

C) The set of all string such that every block of five consecutive symbols
contains at least two 5’s.
%{
#include<stdio.h>
int c=0;
%}

%%
5[0-9][0-9][0-9]5 { c=1; }
5[0-9][0-9]5[0-9] { c=1; }
5[0-9]5[0-9][0-9] { c=1; }
55[0-9][0-9][0-9] { c=1; }
[0-9]5[0-9][0-9]5 { c=1; }
[0-9]5[0-9]5[0-9] { c=1; }
[0-9][0-9]5[0-9]5 { c=1; }
[0-9][0-9][0-9]55 { c=1; }
[0-9]55[0-9][0-9] { c=1; }
[0-9][0-9]55[0-9] { c=1; }
.*[a-zA-Z].* { c=-1; }
.* { c=0; }
%%

int yywrap(){
return 1;
}

int main(){
printf("Enter String: ");
yylex();
if(c==-1)
printf("Invalid String");
else if(c==1)
printf("Accepted");
else
printf("Not accepted");

getch();
return 0;
}

D) The set of all strings beginning with a 1 which, interpreted as the binary
representation of an integer, is congruent to zero modulo 5.
%{
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
int c=0;
int c1=0;
%}

%%

1[0|1]* {
int length =strlen(yytext)-1;
int num=atoi(yytext);
int i=0,base=1;
int count=0;
while(num!=0)
{
int b=num%10;
c+=b*pow(2,count);
num=num/10;
count++;
}
}
. { c1=1; }
%%

int yywrap(void)
{
return 1;
}

int main()
{ printf("Enter a string:");
yylex();
if(c1==1)
printf("Invalid String");
else if(c%5==0 && c1!=1){
printf("The binary number is %d\n",c);
printf("Accepted");
}
else
printf("Not Accepted");
getch();
return 0;
}
E) The set of all strings such that the 10th symbol from the right end is 1.
%{
#include <stdio.h>
int c=0;
%}

%%

[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]1.* { c=1; }
.* { c=0; }

%%
int yywrap(){
return 1;
}

int main() {
printf("Enter the String: ");
yylex();
if(c==1)
printf("Accepted");
else
printf("Not Accepted");
getch();
return 0;
}

F) The set of all four digits numbers whose sum is 9


%{
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
int c=0;
int c1=0;
%}

%%

[1-9][0-9][0-9][0-9] {
int num=atoi(yytext);
while(num!=0)
{
c+=num%10;
num=num/10;
}
}
. { c1=1; }
%%

int yywrap(void)
{
return 1;
}

int main()
{ printf("Enter a string:");
yylex();
if(c1==1)
printf("Invalid String");
else if(c==9 && c1!=1)
printf("Accepted");
else
printf("Not Accepted");
getch();
return 0;
}

G) The set of all four digital numbers, whose individual digits are in ascending
order from left to right
%{
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
int c=0;
int c1=0;
%}

%%

[1-6][2-7][3-8][4-9] { c=1; }
[a-zA-Z]* { c1=1; }
%%

int yywrap(void)
{
return 1;
}

int main()
{ printf("Enter a string:");
yylex();
if(c1==1)
printf("Invalid String");
else if(c==1 && c1!=1)
printf("Accepted");
else
printf("Not Accepted");
getch();
return 0;
}

2. Write a program in LEX to recognize Floating Point Numbers


%{
#include<stdio.h>
int c=0;
%}

%%

[0-9]*\.[0-9]+ { c=1; }
.* { c=0; }
%%
int yywrap(void)
{
return 1;
}
int main()
{ printf("Enter a string:");
yylex();
if(c==1 )
printf("Accepted");
else
printf("Not Accepted");
getch();
return 0;
}

Week-4

1. Write a C Program to Scan and Count the number of characters, words, and lines
in a
file.
Steps to be followed:
a. Take input of a file name and open that file in a read only mode. Don’t
continue if the file can’t be opened.
b. Traverse the file character by character until you get the EOF character. Every
file ends with the EOF character.
i. Increment the character count.
ii. If the character is not a white-space character, set a flag
in_word to 1.
iii. If the character is a white-space and the in_word flag is 1,
increment the word count and set the in_word flag to 0.
iv. If the character is either ‘\n’ or ‘\0’, increment the line count.

Code:-
#include <stdio.h>

int main() {
char filename[100];
FILE *file;
char ch;
int charCount = 0, wordCount = 0, lineCount = 0, in_word = 0;

printf("Enter the file name: ");


scanf("%s", filename);

file = fopen(filename, "r");

if (file == NULL) {
printf("Unable to open the file.\n");
return 0;
}

while ((ch = fgetc(file)) != EOF) {


charCount++;

if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r') {


in_word = 1;
}
else if (in_word) {
wordCount++;
in_word = 0;
}

if (ch == '\n' || ch == '\0') {


lineCount++;
}
}

fclose(file);

printf("Number of characters: %d\n", charCount);


printf("Number of words: %d\n", wordCount);
printf("Number of lines: %d\n", lineCount);

return 0;
}

2. Design a lexical analyzer for given language and the lexical analyzer should
ignore
redundant spaces, tabs and new lines. It should also ignore comments. Although the
syntax specification states that identifiers can be arbitrarily long, you may
restrict the
length to some reasonable value. Simulate the same in C language.

CODE:-
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include<stdlib.h>
int isKeyword(const char *word) {
const char *keywords[] = {"int", "float", "void","char","double","if","else
if","else","return"};
for (int i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
if (strcmp(word, keywords[i]) == 0) {
return 1;
}
}

return 0;
}

bool isComment(const char *word) {


return strstr(word, "//") != NULL || (strstr(word, "/*") != NULL &&
strstr(word, "*/") != NULL);
}
bool isStringLiteral(const char *word) {
return word[0] == '"' && word[strlen(word) - 1] == '"';
}
bool isAssignment(const char *word) {
return strstr(word, "=") != NULL;
}
bool isExpression(const char *word) {
return strstr(word, "+") != NULL || strstr(word, "-") != NULL || strstr(word,
";") != NULL || strstr(word, "*") != NULL || strstr(word, "/") != NULL ||
strstr(word,"<")!=NULL || strstr(word,">")!=NULL || strstr(word,"<=")!=NULL ||
strstr(word,">=")!=NULL || strstr(word,"==")!=NULL;
}
bool isNumber(const char *word) {
char *endptr;
strtod(word, &endptr);
return *endptr == '\0';
}
int main() {
char a[30];
int insideFunction=0;
char identifier[100];
int identifierIndex = 0;
printf("Enter file name: ");
scanf("%s",a);
FILE *ptr;
ptr=fopen(a,"r");
if(ptr==NULL){
printf("File is not opening.");
}
char line[1024];
while (fgets(line, sizeof(line), ptr)) {
if (isComment(line)) {
continue;
}
if (strstr(line, "#include")) {
printf("\n%s : It is a header file...\n", line);
continue;
}
if (strstr(line, "#define")) {
printf("\n%s : It is a Macro..\n", line);
}
char *word = strtok(line, " \t\n");
while (word != NULL) {
if (isKeyword(word)) {
printf("\n%s : It is a Keyword...\n", word);
}
else if (strstr(word, "(")) {
printf("\nFunction: %s(\n)\n", strtok(word, "("));
insideFunction = 1;
}
else if (insideFunction && strstr(word, "{")) {
printf("\nBlock begins { \n");
insideFunction = 0;
}
else if (strstr(word, "}")) {
printf("\nBlock ends }\n");
insideFunction = 0;
}
else if (isAssignment(word)) {
char *identifier = strtok(word, "=");
char *value = strtok(NULL, "=");
if (isNumber(value)) {
printf("\n%s is an identifier = Assignment operator Number\
n", identifier);
} else {
printf("\n%s identifier = Assignment operator \n %s is a
number\n", identifier, value);
}
}
else if (isExpression(word)) {
printf("\nExpression: %s\n", word);
}
else if (isStringLiteral(word)) {
printf("\n%s is String\n", word);
}
else {
if (strstr(word,"printf(\"")) {
printf("String: ");
while (!strstr(word, "\")") && word != NULL) {
printf("\n%s string", word);
word = strtok(NULL, " \t\n");
}
if (word != NULL) {
printf("\n%s\n", word);
}
}
}
word = strtok(NULL, " \t\n");
}
}

fclose(ptr);

return 0;
}

Week-5

Write a program for implementing a Lexical analyser using LEX tool.

%{
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

int isKeyword(const char *word) {


int i;
const char *keywords[] = {"int", "float", "void", "char", "double", "if", "else
if", "else", "return","main"};
for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
if (strcmp(word, keywords[i]) == 0) {
return 1;
}
}
return 0;
}

bool isComment(const char *word) {


return strstr(word, "//") != NULL || (strstr(word, "/*") != NULL &&
strstr(word, "*/") != NULL);
}
bool isStringLiteral(const char *word) {
return word[0] == '"' && word[strlen(word) - 1] == '"';
}

bool isAssignment(const char *word) {


return strstr(word, "=") != NULL;
}

bool isExpression(const char *word) {


return strstr(word, "+") != NULL || strstr(word, "-") != NULL || strstr(word,
";") != NULL ||
strstr(word, "*") != NULL || strstr(word, "/") != NULL || strstr(word,
"<") != NULL ||
strstr(word, ">") != NULL || strstr(word, "<=") != NULL || strstr(word,
">=") != NULL ||
strstr(word, "==") != NULL;
}

bool isNumber(const char *word) {


char *endptr;
strtod(word, &endptr);
return *endptr == '\0';
}
%}
%%
"//".* { }
"/*" {
int commentLevel = 1;
while (commentLevel > 0) {
char c = getchar();
if (c == '*' && getchar() == '/') {
commentLevel--;
} else if (c == '/' && getchar() == '*') {
commentLevel++;
}
}
}
\"[^\"]*\" { printf("String: %s\n", yytext); }
"#include".* {
printf("Preprocessor Directive: %s\n", yytext);
}
"#define".* {
printf("Macro: %s\n", yytext);
}
[ \t\n] ;
[<>=+\-*/;] { if (isExpression(yytext)) {
printf("Expression: %s\n", yytext);
} else {
printf("Operator: %s\n", yytext);
}
}

[0-9]+(\.[0-9]+)? {
if (isNumber(yytext)) {
printf("Number: %s\n", yytext);
}
}
[a-zA-Z_][a-zA-Z_0-9]* {
if (isKeyword(yytext)) {
printf("Keyword: %s\n", yytext);
} else {
printf("Identifier: %s\n", yytext);
}
}

.
%%
int yywrap()
{
return 1;
}
int main() {
yyin = fopen("trail.c", "r");
yylex();
if (!yyin) {
fprintf(stderr, "Failed to open input file\n");
return 1;
}
fclose(yyin);
printf("Press Enter to exit...");
getch();
return 0;
}

WEEK-6

1) Write a Program to Design Recursive Descent Parser


CODE:-
#include <stdio.h>
#include <stdbool.h>

// Function prototypes
bool E();
bool T();
bool match(char token);

char input[100];
int pos = 0;

int main() {
printf("Enter an expression (ending with $): ");
scanf("%s", input);
if (E() && input[pos] == '$') {
printf("Parsing Successful\n");
} else {
printf("Parsing Error\n");
}

return 0;
}

bool E() {
if (input[pos] == 'x') {
pos++;
if (match('+') && T()) {
return true;
}
}
return false;
}

bool T() {
if (input[pos] == '(') {
pos++;
if (E() && match(')')) {
return true;
}
} else if (input[pos] == 'x') {
pos++;
return true;
}
return false;
}

bool match(char token) {


if (input[pos] == token) {
pos++;
return true;
}
return false;
}

WEEK-7

Computation of First and Follow

Rules for Follow Sets


1. First put $ (the end of input marker) in Follow(S) (S is the start symbol)
2. If there is a production A → aBb, (where a can be a whole string) then
everything in
FIRST(b) except for ε is placed in FOLLOW(B).
3. If there is a production A → aB, then everything in FOLLOW(A) is in FOLLOW(B)
4. If there is a production A → aBb, where FIRST(b) contains ε, then everything in
FOLLOW(A) is in FOLLOW(B)
Assumptions
1. Epsilon is represented by ‘#’.
2. Productions are of the form A=B, where ‘A’ is a single Non-Terminal and ‘B’
can be any combination of Terminals and Non- Terminals.
3. L.H.S. of the first production rule is the start symbol.
4. Grammar is not left recursive.
5. Each production of a non-terminal is entered on a different line.
6. Only Upper Case letters are Non-Terminals and everything else is a terminal.
7. Do not use ‘!’ or ‘$’ as they are reserved for special purposes.

CODE: -
#include <stdio.h>
#include <string.h>
#define max 20

char prod[max][10];
char ter[10], nt[10];
char first[10][10], follow[10][10];
int eps[10];
int count_var = 0;
int findpos(char ch) {
int n;
for (n = 0; nt[n] != '\0'; n++)
if (nt[n] == ch)
break;
if (nt[n] == '\0')
return 1;
return n;
}

int IsCap(char c) {
if (c >= 'A' && c <= 'Z')
return 1;
return 0;
}

void add(char *arr, char c) {


int i, flag = 0;
for (i = 0; arr[i] != '\0'; i++) {
if (arr[i] == c) {
flag = 1;
break;
}
}
if (flag != 1)
arr[strlen(arr)] = c;
}

void addarr(char *s1, char *s2) {


int i, j, flag = 99;
for (i = 0; s2[i] != '\0'; i++) {
flag = 0;
for (j = 0;; j++) {
if (s2[i] == s1[j]) {
flag = 1;
break;
}
if (j == strlen(s1) && flag != 1) {
s1[strlen(s1)] = s2[i];
break;
}
}
}
}

void addprod(char *s) {


int i;
prod[count_var][0] = s[0];
for (i = 3; s[i] != '\0'; i++) {
if (!IsCap(s[i]))
add(ter, s[i]);
prod[count_var][i - 2] = s[i];
}
prod[count_var][i - 2] = '\0';
add(nt, s[0]);
count_var++;
}
void findfirst() {
int i, j, n, k, e, n1;
for (i = 0; i < count_var; i++) {
for (j = 0; j < count_var; j++) {
n = findpos(prod[j][0]);
if (prod[j][1] == (char)238)
eps[n] = 1;
else {
for (k = 1, e = 1; prod[j][k] != '\0' && e == 1; k++) {
if (!IsCap(prod[j][k])) {
e = 0;
add(first[n], prod[j][k]);
} else {
n1 = findpos(prod[j][k]);
addarr(first[n], first[n1]);
if (eps[n1] == 0)
e = 0;
}
}
if (e == 1)
eps[n] = 1;
}
}
}
}

void findfollow() {
int i, j, k, n, e, n1;
n = findpos(prod[0][0]);
add(follow[n], '$');
for (i = 0; i < count_var; i++) {
for (j = 0; j < count_var; j++) {
k = strlen(prod[j]) - 1;
for (; k > 0; k--) {
if (IsCap(prod[j][k])) {
n = findpos(prod[j][k]);
if (prod[j][k + 1] == '\0') {
n1 = findpos(prod[j][0]);
addarr(follow[n], follow[n1]);
}
if (IsCap(prod[j][k + 1])) {
n1 = findpos(prod[j][k + 1]);
addarr(follow[n], first[n1]);
if (eps[n1] == 1) {
n1 = findpos(prod[j][0]);
addarr(follow[n], follow[n1]);
}
} else if (prod[j][k + 1] != '\0')
add(follow[n], prod[j][k + 1]);
}
}
}
}
}

int main() {
char s[max], i;
printf("Enter the productions\n");
scanf("%s", s);
while (strcmp("end", s)) {
addprod(s);
scanf("%s", s);
}
findfirst();
findfollow();
printf("%s\t%s\t%s\n","Non-Terminals","First-Set","Follow-Set");
for (i = 0; i < strlen(nt); i++) {
printf("%c\t\t", nt[i]);
printf("{ ");

if (strlen(first[i]) > 0) {
for (int j = 0; j < strlen(first[i]); j++) {
printf("%c", first[i][j]);
if (j < strlen(first[i]) - 1) {
printf(", ");
}
}
}
printf(" }\t\t{ ");

if (strlen(follow[i]) > 0) {
for (int j = 0; j < strlen(follow[i]); j++) {
printf("%c", follow[i][j]);
if (j < strlen(follow[i]) - 1) {
printf(", ");
}
}
}
else {
printf("%s", "na");
}
printf(" }\n");
}
return 0;
}

WEEk -
8

Design of Non-Recursive Predictive Parsing for the grammar


Aim: Write a Program to Design Predictive Parser
Description: We have completed the Lexical Analysis phase. Present, we are in
Syntax
Analysis phase. Syntax Analysis is one of the phases in Compiler Design. Syntax
Analysis is
also known as “Parsing”.
Parsing: Parsing or syntactic analysis is the process of analysing a string of
symbols, either
in natural language or in computer languages, conforming to the rules of a formal
grammar.
The term parsing comes from Latin pars (orationis), meaning part (of speech).
“A parser is a software component that takes input data (frequently text) and
builds a data
structure – often some kind of parse tree, abstract syntax tree or other
hierarchical
structure – giving a structural representation of the input, checking for correct
syntax in
the process.”
Predictive parser is a recursive descent parser, which has the capability to
predict which
production is to be used to replace the input string. The predictive parser does
not suffer from
backtracking.
To accomplish its tasks, the predictive parser uses a look-ahead pointer, which
points to the
next input symbols. To make the parser back-tracking free, the predictive parser
puts some
constraints on the grammar and accepts only a class of grammar known as LL(k)
grammar.

Predictive parsing uses a stack and a parsing table to parse the input and generate
a parse tree.
Both the stack and the input contains an end symbol $ to denote that the stack is
empty and
the input is consumed. The parser refers to the parsing table to take any decision
on the input
and stack element combination.

CODE: -
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_RULES 100


#define MAX_SYMBOLS 100

char FIRST[MAX_SYMBOLS][MAX_SYMBOLS];
char FOLLOW[MAX_SYMBOLS][MAX_SYMBOLS];
char T[MAX_SYMBOLS], NT[MAX_SYMBOLS], G[MAX_RULES][MAX_SYMBOLS],
STACK[MAX_SYMBOLS];
int LL1[MAX_SYMBOLS][MAX_SYMBOLS];

int top = 0, t = 0, nt = 0, cr = 0, count = 0;

void add_symbol(char *arr, char ch) {


if (strchr(arr, ch) == NULL) {
arr[count++] = ch;
arr[count] = '\0';
}
}

void FIND_FIRST(char *arr, char ch) {


if (!isupper(ch))
add_symbol(arr, ch);
else {
for (int i = 0; i < cr; i++) {
if (ch == G[i][0]) {
if (G[i][3] == '!')
add_symbol(arr, G[i][3]);
else
FIND_FIRST(arr, G[i][3]);
}
}
}
}

void FIND_FOLLOW(char arr[], char ch) {


if (ch == G[0][0])
add_symbol(arr, '$');
for (int i = 0; i < cr; i++) {
for (int j = 3; G[i][j] != '\0'; j++) {
if (ch == G[i][j]) {
if (G[i][j + 1] != '\0' && isupper(G[i][j + 1])) {
for (int k = 0; k < nt; k++) {
if (NT[k] == G[i][j + 1]) {
for (int l = 0; FIRST[k][l] != '\0'; l++) {
if (FIRST[k][l] != '\0' && FIRST[k][l] != '!')
add_symbol(arr, FIRST[k][l]);
}
break;
}
}
} else if (G[i][j + 1] != '\0' && !isupper(G[i][j + 1])) {
add_symbol(arr, G[i][j + 1]);
}
if ((G[i][j + 1] == '\0') && G[i][0] != ch)
FIND_FOLLOW(arr, G[i][0]);
}
}
}
}

int CREATE_LL1_TABLE() {
int flag = 0;
for (int i = 0; i < cr; i++) {
char arr[MAX_SYMBOLS];
arr[0] = '\0';
count = 0;
FIND_FIRST(arr, G[i][3]);
for (int j = 0; j < count; j++) {
if (arr[j] == '!') {
FIND_FOLLOW(arr, G[i][0]);
break;
}
}
int pos = -1;
for (int k = 0; k < nt; k++) {
if (NT[k] == G[i][0]) {
pos = k;
break;
}
}
for (int j = 0; j < count; j++) {
if (arr[j] != '!') {
for (int k = 0; k < t; k++) {
if (arr[j] == T[k]) {
if (LL1[pos][k] > 0) {
printf("Conflict occur between %s and %s rules!\n",
G[LL1[pos][k] - 1], G[i]);
printf("Given grammar is not LL(1) grammar!\n");
flag = 1;
return flag;
} else
LL1[pos][k] = i + 1;
break;
}
}
}
}
}
return flag;
}

int main() {
char STR[MAX_SYMBOLS];
int flag, ch1;
printf("Enter production rules of grammar in the form A->B\n\n");
flag = 1;

while (flag == 1) {
printf("\n1) Insert Production Rules\n2) Show Grammar\n3) Exit");
printf("\nEnter your choice: ");
scanf("%d", &ch1);

switch (ch1) {
case 1:
printf("Enter rule %d of grammar: ", cr + 1);
scanf("%s", G[cr++]);

if (!strchr(NT, G[cr - 1][0])) {


NT[nt++] = G[cr - 1][0];
}

for (int i = 3; G[cr - 1][i] != '\0'; i++) {


if (!isupper(G[cr - 1][i]) && G[cr - 1][i] != '!') {
if (!strchr(T, G[cr - 1][i])) {
T[t++] = G[cr - 1][i];
}
}
}
break;

case 2:
if (cr > 0) {
printf("\nGrammar\n");
printf("Starting symbol is: %c\n", G[0][0]);
printf("Non-terminal symbols: ");
for (int i = 0; i < nt; i++)
printf("%c ", NT[i]);
printf("\nTerminal symbols: ");
for (int i = 0; i < t; i++)
printf("%c ", T[i]);
printf("\nProduction rules: ");
for (int i = 0; i < cr; i++)
printf("%s ", G[i]);
printf("\n");
} else {
printf("Enter at least one production rule.\n");
}
break;

case 3:
flag = 0;
break;
}
}

FIRST_SHOW();
FOLLOW_SHOW();

T[t++] = '$';
T[t] = '\0';

flag = CREATE_LL1_TABLE();
PARSING_TABLE_SHOW(flag);

if (flag == 0) {
printf("Enter string for parsing: ");
scanf("%s", STR);
LL1_PARSER(STR);
}
return 0;
}

void FIRST_SHOW() {
for (int i = 0; i < nt; i++) {
char arr[MAX_SYMBOLS] = "";
FIND_FIRST(arr, NT[i]);
strcpy(FIRST[i], arr);
}
printf("\nFIRST:\n\n");
for (int i = 0; i < nt; i++) {
printf("FIRST( %c ): { %s }\n", NT[i], FIRST[i]);
}
}

void FOLLOW_SHOW() {
for (int i = 0; i < nt; i++) {
count = 0;
char arr[MAX_SYMBOLS] = "";
FIND_FOLLOW(arr, NT[i]);
strcpy(FOLLOW[i], arr);
}
printf("\nFOLLOW:\n\n");
for (int i = 0; i < nt; i++) {
printf("FOLLOW( %c ): { %s }\n", NT[i], FOLLOW[i]);
}
}

void PARSING_TABLE_SHOW(int flag) {


if (flag == 0) {
printf("\n\nPredictive Parsing Table:\n\n\t");
for (int j = 0; j < t; j++) {
printf("\t%c\t", T[j]);
}
printf("\
n----------------------------------------------------------------------------------
------");
printf("\n\n");
for (int i = 0; i < nt; i++) {
printf("%c\t|\t", NT[i]);
for (int j = 0; j < t; j++) {
if (LL1[i][j] != 0)
printf("%s\t\t", G[LL1[i][j] - 1]);
else
printf("%c\t\t", '_');
}
printf("\n\n");
}
}
}

void LL1_PARSER(char *STR) {


int i = 0, j, pos, pos1, n, k;

STR[strlen(STR)] = '$';
STACK[top++] = '$';
STACK[top] = G[0][0];

printf("\nParsing sequence and actions\n\n");


printf("STACK\t\t\tINPUT\t\t\tACTION");
printf("\
n----------------------------------------------------------------------------------
--\n");

i = 0;
while (STACK[top] != '$') {
for (j = 0; STACK[j] != '\0'; j++)
printf("%c ", STACK[j]);
printf("\t\t");

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


printf("%c ", STR[j]);

if (STR[i] == STACK[top]) {
printf("\t\tShift: %c", STACK[top]);
STACK[top] = '\0';
top = top - 1;
i = i + 1;
} else {
for (j = 0; j < nt; j++) {
if (STACK[top] == NT[j]) {
pos = j;
break;
}
}
for (j = 0; j < t; j++) {
if (STR[i] == T[j]) {
pos1 = j;
break;
}
}
n = LL1[pos][pos1];
if (G[n - 1][3] == '!') {
STACK[top] = '\0';
top--;
} else {
for (j = 3; G[n - 1][j] != '\0'; j++)
k = j;
STACK[top] = '\0';
for (j = k; j > 2; j--)
STACK[top++] = G[n - 1][j];
top--;
}
printf("\t\tReplace(in Reverse): %s", G[n - 1]);
}
printf("\n");
}
for (j = 0; STACK[j] != '\0'; j++)
printf("%c ", STACK[j]);
printf("\t\t");

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


printf("%c ", STR[j]);

printf("\n");
if (STACK[top] == '$' && STR[i] == '$')
printf("\nParsing successfully\n");
}

WEEK -
9

Aim: Implementation of Shift reduce parser


Description: Shift-reduce Parsing (Bottom-up Parsing) Shift-reduce parsing attempts
to
construct a parse tree for an input string beginning at the leaves and working up
towards the
root. In other words, it is a process of “reducing” (opposite of deriving a symbol
using a
production rule) a string w to the start symbol of a grammar.
Bottom-up parsing starts from the leaf nodes of a tree and works in upward
direction till it
reaches the root node. Here, we start from a sentence and then apply production
rules in
reverse manner in order to reach the start symbol. The image given below depicts
the
bottom-up parsers available.

Shift-Reduce Parsing
Shift-reduce parsing uses two unique steps for bottom-up parsing. These steps are
known as
shift-step and reduce-step.
Shift step: The shift step refers to the advancement of the input pointer to the
next
input symbol, which is called the shifted symbol. This symbol is pushed onto the
stack. The shifted symbol is treated as a single node of the parse tree.
Reduce step: When the parser finds a complete grammar rule (RHS) and replaces it
to (LHS), it is known as reduce-step. This occurs when the top of the stack
contains a
handle. To reduce, a POP function is performed on the stack which pops off the
handle and replaces it with LHS non-terminal symbol.
CODE: -
#include <stdio.h>
#include <string.h>
int z = 0, i = 0, j = 0, c = 0;
char a[20], ac[20], stk[20], act[10];
void check() {
strcpy(ac, "REDUCE TO ");
for (z = 0; z < c; z++) {
if (stk[z] == '(' && stk[z + 1] == 'E' && stk[z + 2] == ')') {
printf("%s E->(E)", ac);
stk[z] = 'E';
stk[z + 1] = '\0';
stk[z + 2] = '\0';
printf("\n$%s\t%s$\t", stk, a);
}
if (stk[z] == 'E' && stk[z + 1] == '*' && stk[z + 2] == 'E') {
printf("%s E->E*E", ac);
stk[z] = 'E';
stk[z + 1] = '\0';
stk[z + 2] = '\0';
printf("\n$%s\t%s$\t", stk, a);
i = i - 2;
}
if (stk[z] == 'E' && stk[z + 1] == '+' && stk[z + 2] == 'E') {
printf("%s E->E+E", ac);
stk[z] = 'E';
stk[z + 1] = '\0';
stk[z + 2] = '\0';
printf("\n$%s\t%s$\t", stk, a);
i = i - 2;
}
if (stk[z] == 'd') {
printf("%s E-> d", ac);
stk[z] = 'E';
stk[z + 1] = '\0';
printf("\n$%s\t%s$\t", stk, a);
}
}
return;
}
int main() {
printf("GRAMMAR is -\nE->E+E\nE->E*E\nE->(E)\nE->d\n");
char a1[100];
printf("Enter A String: ");
scanf("%s", a1);
strcpy(a, a1);
c = strlen(a);
strcpy(act, "SHIFT");
printf("\nstack \t input \t action");
printf("\n$\t%s$\t", a);
for (i = 0, j = 0; j < c; i++, j++) {
printf("%s", act);
stk[i] = a[j];
stk[i + 1] = '\0';
a[j] = ' ';
printf("\n$%s\t%s$\t", stk, a);
check();
}
check();
if (stk[0] == 'E' && stk[1] == '\0' && a[j] == '\0') {
printf("ACCEPT\nInput successfully parsed.\n");
} else {
printf("REJECT\nInput cannot be parsed.\n");
}
return 0;
}

WEEK -
10

Aim: YACC Specification for a simple desk calculator


Description:
Yacc (for “yet another compiler compiler.”) is the standard parser generator for
the Unix
operating system. An open source program, yacc generates code for the parser in the
C
programming language. The acronym is usually rendered in lowercase but is
occasionally
seen as YACC or Yacc.

YAAC FILE(.Y):-
%{
#include<stdio.h>
int flag=0;
%}

%token NUMBER

%left '+' '-'

%left '*' '/' '%'

%left '(' ')'

/* Rule Section */
%%

ArithmeticExpression: E{

printf("\nResult=%d\n", $$);

return 0;

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

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

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

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

|E'%'E {$$=$1%$3;}

|'('E')' {$$=$2;}
| NUMBER {$$=$1;}

%%

//driver code
void main()
{
printf("\nEnter Any Arithmetic Expression which can have operations Addition,
Subtraction, Multiplication, Division, Modulus and Round brackets:\n");

yyparse();
if(flag==0)
printf("\nEntered arithmetic expression is Valid\n\n");
getch();
}

void yyerror()
{
printf("\nEntered arithmetic expression is Invalid\n\n");
flag=1;
}

LEX CODE(.l): -
%{
#include<stdio.h>
#include "y.tab.h"
extern int yylval;
%}

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

}
[\t] ;

[\n] return 0;

. return yytext[0];

%%

int yywrap()
{
return 1;
}

WEEK-
11

AIM: - Write code to implement LALR (1) parser

CODE (. Y) :-
%{
#include <stdio.h>
int flag = 0;
int yylex();
%}

%token NUMBER SPECIAL_CHAR


%left '+' '-'
%left '*' '/' '%'
%left '(' ')'
%nonassoc '!' '@' '#' '$' '^' '&' '_' '~' '`'
%%

ArithmeticExpression: E {
/*printf("\nResult = %d\n", $1);*/
return 0;
};

E: E '+' E { $$ = $1 + $3; }
| E '-' E { $$ = $1 - $3; }
| E '*' E { $$ = $1 * $3; }
| E '/' E { $$ = $1 / $3; }
| E '%' E { $$ = $1 % $3; }
| '(' E ')' { $$ = $2; }
| NUMBER { $$ = $1; }
| E'!'E { yyerror(); }
| E '@' E { yyerror(); }
| E '#' E { yyerror(); }
| E '$' E { yyerror(); }
| E '^' E { yyerror(); }
| E '&' E { yyerror(); }
| E '_' E { yyerror(); }
| E '~' E { yyerror(); }
| E '`' E { yyerror(); }
;

%%

void yyerror(const char* s) {


printf("String cannot be generated\n", s);
flag = 1;
}

int main() {
printf("\nEnter Any Infix Expression:");
yyparse();
if (flag == 0)
printf("\nString can be generated");
getch();
return 0;
}

CODE (. l): -
%{
#include<stdio.h>
#include "y.tab.h"
extern int yylval;
%}

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

}
[\t] ;

[\n] return 0;
[-+*/%()] { return yytext[0]; }

. return yytext[0];

%%

int yywrap()
{
return 1;
}

WEEEK-12

Aim: To write a C program to implement Implementation of Intermediate code


generator
Description:
• A source code can directly be translated into its target machine code, then
why at all we
• need to translate the source code into an intermediate code which is then
translated to its
• target code? Let us see the reasons why we need an intermediate code.
• If a compiler translates the source language to its target machine language
without
• having the option for generating intermediate code, then for each new
machine, a full
• native compiler is required.
• Intermediate code eliminates the need of a new full compiler for every unique
• machine by keeping the analysis portion same for all the compilers.
• The second part of compiler, synthesis, is changed according to the target
machine.
• It becomes easier to apply the source code modifications to improve code
• performance by applying code optimization techniques on the intermediate
code.

CODE: -
#include <stdio.h>
#include <string.h>
int i = 1, j = 0, no = 0, tmpch = 90;
char str[100], left[15], right[15];
struct exp {
int pos;
char op;
} k[15];
void findOperators();
void explore();
void extractLeftOperand(int);
void extractRightOperand(int);
int main() {
printf("\t\tINTERMEDIATE CODE GENERATION\n\n");
printf("Enter the Expression: ");
scanf("%s", str);
findOperators();
explore();

return 0;
}
void findOperators() {
const char operators[] = {':', '/', '*', '+', '-'};

for (int opIndex = 0; opIndex < sizeof(operators) / sizeof(operators[0]);


opIndex++) {
for (i = 0; str[i] != '\0'; i++) {
if (str[i] == operators[opIndex]) {
k[j].pos = i;
k[j++].op = operators[opIndex];
}
}
}
}
void explore() {
i = 1;
while (k[i].op != '\0') {
extractLeftOperand(k[i].pos);
extractRightOperand(k[i].pos);
str[k[i].pos] = tmpch--;
printf("\t%c := %s%c%s\t\t", str[k[i].pos], left, k[i].op, right);
printf("\n");
i++;
}
extractRightOperand(-1);
if (no == 0) {
extractLeftOperand(strlen(str));
printf("\t%s := %s", right, left);
getchar();
return;
}
printf("\t%s := %c", right, str[k[--i].pos]);
getchar();
}
void extractLeftOperand(int x) {
int w = 0, flag = 0;
x--;
while (x != -1 && str[x] != '+' && str[x] != '*' && str[x] != '=' && str[x] !=
'\0' && str[x] != '-' && str[x] != '/') {
if (str[x] != '$' && flag == 0) {
left[w++] = str[x];
left[w] = '\0';
str[x] = '$';
flag = 1;
}
x--;
}
}
void extractRightOperand(int x) {
int w = 0, flag = 0;
x++;
while (x != -1 && str[x] != '+' && str[x] != '*' && str[x] != '\0' && str[x] !=
'=' && str[x] != '-' && str[x] != '/') {
if (str[x] != '$' && flag == 0) {
right[w++] = str[x];
right[w] = '\0';
str[x] = '$';
flag = 1;
}
x++;
}
}

You might also like