CC Lab 1-4
CC Lab 1-4
CSE304
Practical file
Submitted by:
Krish Dogra
A2305222573
6CSE-9X
Submitted to:
Dr Roshan Lal
Experiment 1
Aim: Write a program to identify keywords, constants, special characters and
identifiers from a given input string.
Language Used: C
Theory: Lexical analysis is a fundamental part of compiler design, where a
given input string is processed to identify meaningful components called tokens.
Tokens include keywords, constants, special characters, and identifiers, each
playing a crucial role in programming languages.
Keywords are predefined reserved words such as int, return, and if, which have
specific meanings in the C programming language. Constants refer to fixed
numeric values like 100 or 3.14, which do not change during execution.
Identifiers are user-defined names for variables, functions, and arrays, following
the language's naming conventions. Special characters include symbols like +,
-, *, {, }, which define operations and control structures in the code.
The program reads an input string, processes each character, and groups them
into tokens based on predefined rules. It scans the string, checks whether a
sequence of characters matches a keyword, a constant, or an identifier, and
detects special symbols. This process ensures accurate token classification,
which is crucial for syntax analysis in a compiler.
Lexical analysis is essential for code parsing, debugging, and compilation, as it
helps detect syntax errors early. By systematically breaking the input into
tokens, the program enhances readability and assists in further stages of code
execution, such as semantic analysis and optimization.
Code:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
const char *keywords[] = {"int", "float", "char", "double", "return", "if",
"else", "for", "while", "do", "switch", "case", "break", "continue", "void",
"static", "struct", "typedef", "const", "sizeof", "volatile", "enum", "union",
"default", "extern", "goto", "register", "short", "signed", "unsigned", "long",
"auto", "inline", "restrict", "_Alignas", "_Alignof", "_Atomic", "_Bool",
"_Complex", "_Generic", "_Imaginary", "_Noreturn", "_Static_assert",
"_Thread_local"};
int keyword_count = sizeof(keywords) / sizeof(keywords[0]);
int main() {
char nonTerminal;
int prodCount;
char productions[MAX][MAX];
printf("Enter the non-terminal: ");
scanf(" %c", &nonTerminal);
printf("Enter the number of productions: ");
scanf("%d", &prodCount);
printf("Enter the productions (e.g., A->Aa|b, enter only 'Aa' and 'b'):\n");
for (int i = 0; i < prodCount; i++) {
scanf("%s", productions[i]);
}
printf("\nGrammar after removing left recursion:\n");
removeLeftRecursion(nonTerminal, productions, prodCount);
return 0;
}
Output:
Experiment 4
Aim: Write a program to check whether a given grammar is LL(1).
Language Used: C
Theory:
LL(1) parsing is a top-down method that uses a parsing table to decide the next
action. A grammar is LL(1) if:
1. No Left Recursion – Avoids infinite loops.
2. No Ambiguity – Each parsing table cell has at most one production.
3. No Left Factoring – No common prefixes in productions.
To check if a grammar is LL(1):
1. Compute First and Follow sets.
2. Build the Parsing Table using these sets.
3. If any cell has multiple entries, the grammar is not LL(1).
This ensures efficient predictive parsing without backtracking.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 10
typedef struct {
char nonTerminal;
char productions[MAX][MAX];
int prodCount;
char first[MAX];
char follow[MAX];
} Grammar;
int n;
Grammar grammar[MAX];
if (checkLL1()) {
printf("The given grammar is LL(1).\n");
} else {
printf("The given grammar is NOT LL(1).\n");
}
return 0;
}
Output: