0% found this document useful (0 votes)
10 views42 pages

CDFile

Uploaded by

KP
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)
10 views42 pages

CDFile

Uploaded by

KP
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/ 42

DELHI TECHNOLOGICAL UNIVERSITY

DEPARTMENT OF COMPUTER SCIENCE AND ENGINEERING

CO-302(P) Compiler Design

Practical File

SUBMITTED TO: SUBMITTED BY:


Dr. RK Yadav Krishna Poddar
(2K21/CO/243)

1
INDEX
S. no. Program Date Page No. Signature
1 Write a program to convert Non-Deterministic Finite 3-5
Automata (NFA) to Deterministic Finite Automata
(DFA).
2 Write a program for acceptance of string by DFA 6-7

3 Write a program to find different tokens in a 8-11


program.

4 Write a program to implement lexical analyser. 12-14

5 Write a program to implement recursive descent 15-18


parser.

6 Write a program to implement left factoring. 19-22

7 Write a program to convert left recursive grammar 23-25


to right recursive grammar

8 Write a program to compute First and Follow. 26-31

9 Write a program to construct LL(1) parsing table 32-34

10 Write a program to implement non recursive descent 35-37


predictive parsing.

11 Write a program to implement an error handler. 38-39

12 Write a program to implement one pass compiler. 40-42

2
EXPERIMENT -1
AIM: Write a program to convert Non-Deterministic Finite Automata (NFA) to Deterministic
Finite Automata (DFA)..

THEORY:

Deterministic Finite Automata

A DFA can be represented by a 5-tuple (Q, ∑, δ, q0, F) where −

Q is a finite set of states.

∑ is a finite set of symbols called the alphabet.

δ is the transition function where δ: Q × ∑ → Q

q0 is the initial state from where any input is processed (q0 ∈ Q).

F is a set of final state/states of Q (F ⊆ Q).

Non-Deterministic Finite Automata

Formal Definition of an NDFA An NDFA can be represented by a 5-tuple (Q, ∑, δ, q0, F)

where − Q is a finite set of states.

∑ is a finite set of symbols called the alphabets.

δ is the transition function where δ: Q × ∑ → 2Q (Here the power set of Q (2Q ) has been taken
because in case of NDFA, from a state, transition can occur to any combination of Q states)

q0 is the initial state from where any input is processed (q0 ∈ Q).

F is a set of final state/states of Q (F ⊆ Q).

Steps for converting NFA to DFA:

Step 1: Initially Q' = ϕ

Step 2: Add q0 of NFA to Q'. Then find the transitions from this start state.

Step 3: In Q', find the possible set of states for each input symbol. If this set of states is not in Q',
then add it to Q'.

3
Step 4: In DFA, the final state will be all the states which contain F(final states of NFA)

CODE:
1 import java.util.*;
2 public class NFAtoDFA {
3 private static Map<Set<String>, Map<Character, Set<String>>>
nfaTransitions;
4 private static Set<String> nfaStates;
5 private static Set<String> nfaFinalStates;
6 private static Set<Character> nfaAlphabet;
7
8 private static Map<Set<String>, Map<Character, Set<String>>>
dfaTransitions;
9 private static Set<Set<String>> dfaStates;
10 private static Set<Set<String>> dfaFinalStates;
11
12 public static void main(String[] args) {
13 // Define the NFA
14 nfaStates = new HashSet<>(Set.of("q0", "q1", "q2", "q3"));
15 nfaAlphabet = new HashSet<>(Set.of('a', 'b'));
16 nfaFinalStates = new HashSet<>(Set.of("q2", "q3"));
17
18 nfaTransitions = new HashMap<>();
19 nfaTransitions.put(Set.of("q0"), Map.of('a', Set.of("q1", "q0"), 'b',
Set.of("q0")));
20 nfaTransitions.put(Set.of("q1"), Map.of('a', Set.of("q2"), 'b',
Set.of("q1", "q3")));
21 nfaTransitions.put(Set.of("q2"), Map.of('a', Set.of("q2"), 'b',
Set.of("q2")));
22 nfaTransitions.put(Set.of("q3"), Map.of('a', Set.of("q3"), 'b',
Set.of("q3")));
23
24 // Convert the NFA to a DFA
25 convertNFAtoDFA();
26
27 // Print the resulting DFA
28 System.out.println("DFA States: " + dfaStates);
29 System.out.println("DFA Final States: " + dfaFinalStates);
30 System.out.println("DFA Transitions: " + dfaTransitions);
31 }
32
33 private static void convertNFAtoDFA() {
34 dfaStates = new HashSet<>();
35 dfaFinalStates = new HashSet<>();
36 dfaTransitions = new HashMap<>();
37
38 // Create the initial DFA state from the NFA's start state
39 Set<String> initialState = new HashSet<>(Set.of("q0"));
40 dfaStates.add(initialState);
41 if (nfaFinalStates.stream().anyMatch(initialState::contains)) {
42 dfaFinalStates.add(initialState);
43 }
44
45 // Perform a breadth-first search to find all reachable DFA states
46 Queue<Set<String>> queue = new LinkedList<>();
47 queue.offer(initialState);
48
49 while (!queue.isEmpty()) {
50 Set<String> currentState = queue.poll();

4
51 for (char symbol : nfaAlphabet) {
52 Set<String> nextState = new HashSet<>();
53 for (String state : currentState) {
54
nextState.addAll(nfaTransitions.get(Set.of(state)).get(symbol));
55 }
56
57 if (!dfaStates.contains(nextState)) {
58 dfaStates.add(nextState);
59 if (nfaFinalStates.stream().anyMatch(nextState::contains))
{
60 dfaFinalStates.add(nextState);
61 }
62 queue.offer(nextState);
63 }
64
65 if (!dfaTransitions.containsKey(currentState)) {
66 dfaTransitions.put(currentState, new HashMap<>());
67 }
68 dfaTransitions.get(currentState).put(symbol, nextState);
69 }
70 }
71 }
72 }

OUTPUT:

5
EXPERIMENT 2
AIM:Write a program for acceptance of string by DFA

THEORY:
A DFA accepts a string when its transitions, starting from the initial state, result in an accepting
state. Similarly, a language is accepted by a DFA if all strings in the language lead to acceptance,
meaning they result in the DFA reaching an accepting state. If any string fails to lead to
acceptance, the entire language is rejected by the DFA.

Example:

This DFA accepts all strings that having at least one “a”. Like string ba, bbbab, aaab are accepted
but string bbbb is rejected.

CODE:

1 import java.util.*;
2 public class DFAAcceptor {
3 private static Map<String, Map<Character, String>> dfaTransitions;
4 private static Set<String> dfaStates;
5 private static Set<String> dfaFinalStates;
6
7 public static void main(String[] args) {
8 // Define the DFA
9 dfaStates = new HashSet<>(Set.of("q0", "q1", "q2", "q3"));
10 dfaFinalStates = new HashSet<>(Set.of("q2", "q3"));
11
12 dfaTransitions = new HashMap<>();
13 dfaTransitions.put("q0", Map.of('a', "q1", 'b', "q0"));
14 dfaTransitions.put("q1", Map.of('a', "q2", 'b', "q1"));
15 dfaTransitions.put("q2", Map.of('a', "q2", 'b', "q2"));
16 dfaTransitions.put("q3", Map.of('a', "q3", 'b', "q3"));
17
18 // Test the string’s acceptance with DFA
19 while(true){

6
20 System.out.println("Enter the String to check
acceptance with the DFA: ");
21
22 Scanner sc=new Scanner(System.in);
23 String input=sc.nextLine();
24 System.out.println(acceptString(input));
25 }
26 }
27
28 private static boolean acceptString(String input) {
29 String currentState = "q0";
30
31 for (char symbol : input.toCharArray()) {
32 if
(!dfaTransitions.get(currentState).containsKey(symbol)) {
33 return false;
34 }
35 currentState =
dfaTransitions.get(currentState).get(symbol);
36 }
37
38 return dfaFinalStates.contains(currentState);
39 }
40 }
41

OUTPUT:

7
EXPERIMENT 3
AIM:Write a program to find different tokens in a program.
THEORY:
Token:
A token, within the context of programming languages, refers to a consecutive sequence
of characters that functions as a singular unit within the language's grammar.
Examples of tokens include:
• Type tokens (e.g., identifiers, integers, decimals)
• Punctuation tokens (such as reserved words like "if," "void," "return," etc.)
• Alphabetic tokens (including keywords like "for," "while," "if," etc.)
• Keywords (e.g., "for," "while," "if," etc.)
• Identifiers (e.g., variable names, function names, etc.)
• Operators (e.g., '+', '++', '-', etc.)
• Separators (e.g., ',', ';', etc.)
• Examples of Non-Tokens: Comments, preprocessor directives, macros,
whitespace characters (such as blanks, tabs, newlines), etc.
Lexeme:
A lexeme is the specific sequence of characters that corresponds to a token, or the input
characters forming a single token. For instance, "float," "maximumTemperature," "=", "-
", "2024," and ";" are all examples of lexemes.
CODE:
1 import java.util.*;
2 import java.io.BufferedReader;
3 import java.io.FileReader;
4 import java.io.IOException;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.Map;
8 import java.util.Set;
9
10 public class Tokenizer {
11 private static Map<String, Pair<String, Integer>> table = new
HashMap<>();
12 private static Set<String> keywords = new HashSet<>();
13 private static Set<String> operators = new HashSet<>();
14
15 private static class Pair<T, U> {
16 T first;
17 U second;
18
19 Pair(T first, U second) {
20 this.first = first;
21 this.second = second;
22 }
23 }
24
25 public static void main(String[] args) {
26 String[] javaKeywordArray = {

8
27 "abstract", "assert", "boolean", "break", "byte", "case",
"catch", "char", "class", "const",
28 "continue", "default", "do", "double", "else", "enum",
"extends", "final", "finally", "float",
29 "for", "goto", "if", "implements", "import",
"instanceof", "int", "interface", "long", "native",
30 "new", "package", "private", "protected", "public",
"return", "short", "static", "strictfp",
31 "super", "switch", "synchronized", "this", "throw",
"throws", "transient", "try", "void",
32 "volatile", "while"
33 };
34 keywords.addAll(Set.of(javaKeywordArray));
35
36 String[] operatorArray = {
37 "+", "-", "*", "/", "=", "==", "!=", ">", "<", ">=",
"<=", "++", "--", "+=", "-=", "*=", "/=",
38 "%=", "&=", "|=", "^=", "<<", ">>", ">>>", "&&", "||",
"!", "~", "?", ":"
39 };
40 operators.addAll(Set.of(operatorArray));
41
42 try (BufferedReader reader = new BufferedReader(new
FileReader("C:\\Users\\krish\\OneDrive\\Desktop\\untitled1\\src\\BitStuffing.j
ava"))) {
43 String line;
44 while ((line = reader.readLine()) != null) {
45 if (line.startsWith("//")) {
46 continue;
47 }
48 int i = 0;
49 while (i < line.length()) {
50 StringBuilder temp = new StringBuilder();
51 if (line.charAt(i) == ' ' || line.charAt(i) == '\t')
{
52 while (i < line.length() && (line.charAt(i) == '
' || line.charAt(i) == '\t')) {
53 i++;
54 }
55 } else if (Character.isLetter(line.charAt(i)) ||
line.charAt(i) == '_') {
56 while (i < line.length() &&
(Character.isLetterOrDigit(line.charAt(i)) || line.charAt(i) == '_')) {
57 temp.append(line.charAt(i++));
58 }
59 String word = temp.toString();
60 if (keywords.contains(word)) {
61 table.merge(word, new Pair<>("Keyword", 1),
(oldValue, newValue) -> new Pair<>(oldValue.first, oldValue.second + 1));
62 } else {
63 table.merge(word, new Pair<>("Identifier",
1), (oldValue, newValue) -> new Pair<>(oldValue.first, oldValue.second + 1));
64 }
65 temp.setLength(0);
66 } else if (Character.isDigit(line.charAt(i))) {
67 while (i < line.length() &&
(Character.isDigit(line.charAt(i)) || line.charAt(i) == '.')) {
68 temp.append(line.charAt(i++));
69 }

9
70 table.merge(temp.toString(), new
Pair<>("Constant/Literal", 1), (oldValue, newValue) -> new
Pair<>(oldValue.first, oldValue.second + 1));
71 temp.setLength(0);
72 } else {
73 while (i < line.length() &&
!Character.isLetterOrDigit(line.charAt(i)) && line.charAt(i) != '_') {
74 temp.append(line.charAt(i));
75 String symbol = temp.toString();
76 if (operators.contains(symbol)) {
77 // Check if the current symbol + next
character forms a compound operator
78 if (i + 1 < line.length() &&
operators.contains(symbol + line.charAt(i + 1))) {
79 symbol += line.charAt(i + 1);
80 }
81 table.merge(symbol, new
Pair<>("Operator", 1), (oldValue, newValue) -> new Pair<>(oldValue.first,
oldValue.second + 1));
82 i++;
83 break; // Break out of the loop after
identifying the operator
84 }
85 i++;
86 }
87 temp.setLength(0);
88 }
89 }
90 }
91 } catch (IOException e) {
92 e.printStackTrace();
93 }
94
95 for (Map.Entry<String, Pair<String, Integer>> entry :
table.entrySet()) {
96 System.out.printf("Name: %s, Type: %s, Count: %d%n",
entry.getKey(), entry.getValue().first, entry.getValue().second);
97 }
98 }
99 }

OUTPUT:

10
11
EXPERIMENT 4
AIM:Write a program to implement lexical analyser.

THEORY:
A lexical analyzer, also known as a lexer or scanner, is the first phase of a compiler front-end. It
takes the source code as input and breaks it into a sequence of tokens, which are meaningful
sequences of characters. These tokens can be identifiers, keywords, operators, separators, and
literals.
The process involves reading the input characters and grouping them into tokens based on
predefined patterns or rules. Regular expressions and finite automata are commonly used
techniques to describe these patterns.

CODE:
1 import java.util.*;
2 import java.io.BufferedReader;
3 import java.io.FileReader;
4 import java.io.IOException;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.Map;
8 import java.util.Set;
9
10 public class LexicalAnalyzer {
11 private static Map<String, Pair<String, Integer>> table = new
HashMap<>();
12 private static Set<String> keywords = new HashSet<>();
13 private static Set<String> operators = new HashSet<>();
14
15 private static class Pair<T, U> {
16 T first;
17 U second;
18
19 Pair(T first, U second) {
20 this.first = first;
21 this.second = second;
22 }
23 }
24
25 public static void main(String[] args) {
26 String[] javaKeywordArray = {
27 "abstract", "assert", "boolean", "break", "byte", "case",
"catch", "char", "class", "const",
28 "continue", "default", "do", "double", "else", "enum",
"extends", "final", "finally", "float",
29 "for", "goto", "if", "implements", "import",
"instanceof", "int", "interface", "long", "native",
30 "new", "package", "private", "protected", "public",
"return", "short", "static", "strictfp",
31 "super", "switch", "synchronized", "this", "throw",
"throws", "transient", "try", "void",
32 "volatile", "while"
33 };

12
34 keywords.addAll(Set.of(javaKeywordArray));
35
36 String[] operatorArray = {
37 "+", "-", "*", "/", "=", "==", "!=", ">", "<", ">=",
"<=", "++", "--", "+=", "-=", "*=", "/=",
38 "%=", "&=", "|=", "^=", "<<", ">>", ">>>", "&&", "||",
"!", "~", "?", ":"
39 };
40 operators.addAll(Set.of(operatorArray));
41
42 try (BufferedReader reader = new BufferedReader(new
FileReader("C:\\Users\\krish\\OneDrive\\Desktop\\untitled1\\src\\Example.java"
))) {
43 String line;
44 while ((line = reader.readLine()) != null) {
45 if (line.startsWith("//")) {
46 continue;
47 }
48 int i = 0;
49 while (i < line.length()) {
50 StringBuilder temp = new StringBuilder();
51 if (line.charAt(i) == ' ' || line.charAt(i) == '\t')
{
52 while (i < line.length() && (line.charAt(i) == '
' || line.charAt(i) == '\t')) {
53 i++;
54 }
55 } else if (Character.isLetter(line.charAt(i)) ||
line.charAt(i) == '_') {
56 while (i < line.length() &&
(Character.isLetterOrDigit(line.charAt(i)) || line.charAt(i) == '_')) {
57 temp.append(line.charAt(i++));
58 }
59 String word = temp.toString();
60 if (keywords.contains(word)) {
61 table.merge(word, new Pair<>("Keyword", 1),
(oldValue, newValue) -> new Pair<>(oldValue.first, oldValue.second + 1));
62 } else {
63 table.merge(word, new Pair<>("Identifier",
1), (oldValue, newValue) -> new Pair<>(oldValue.first, oldValue.second + 1));
64 }
65 temp.setLength(0);
66 } else if (Character.isDigit(line.charAt(i))) {
67 while (i < line.length() &&
(Character.isDigit(line.charAt(i)) || line.charAt(i) == '.')) {
68 temp.append(line.charAt(i++));
69 }
70 table.merge(temp.toString(), new
Pair<>("Constant/Literal", 1), (oldValue, newValue) -> new
Pair<>(oldValue.first, oldValue.second + 1));
71 temp.setLength(0);
72 } else {
73 while (i < line.length() &&
!Character.isLetterOrDigit(line.charAt(i)) && line.charAt(i) != '_') {
74 temp.append(line.charAt(i));
75 String symbol = temp.toString();
76 if (operators.contains(symbol)) {
77 // Check if the current symbol + next
character forms a compound operator

13
78 if (i + 1 < line.length() &&
operators.contains(symbol + line.charAt(i + 1))) {
79 symbol += line.charAt(i + 1);
80 }
81 table.merge(symbol, new
Pair<>("Operator", 1), (oldValue, newValue) -> new Pair<>(oldValue.first,
oldValue.second + 1));
82 i++;
83 break; // Break out of the loop after
identifying the operator
84 }
85 i++;
86 }
87 temp.setLength(0);
88 }
89 }
90 }
91 } catch (IOException e) {
92 e.printStackTrace();
93 }
94
95 for (Map.Entry<String, Pair<String, Integer>> entry :
table.entrySet()) {
96 System.out.printf("Name: %s, Type: %s, Count: %d%n",
entry.getKey(), entry.getValue().first, entry.getValue().second);
97 }
98 }
99 }

OUTPUT:
Java code used for analysis: Output of the analysis:

14
EXPERIMENT 5
AIM: Write a program to implement recursive descent parser.

THEORY:
Recursive descent parsing is a top-down parsing method where the parse tree is built from the
top while reading the input from left to right. It employs procedures for each terminal and non-
terminal symbol. This approach recursively analyzes the input to create a parse tree, which might
involve backtracking. However, if the grammar is not left-factored, backtracking cannot be
avoided. A variant of recursive descent parsing that eliminates the need for backtracking is called
predictive parsing. This parsing method is labeled recursive because it utilizes context-free
grammar, which inherently includes recursion.

CODE:

1 import java.util.Scanner;
2
3 public class RecursiveDescentParser {
4
5 public static void main(String[] args) {
6 Scanner scanner = new Scanner(System.in);
7 System.out.println("Original Grammar");
8 System.out.println("E -> E + T | T");
9 System.out.println("T -> T * F | F");
10 System.out.println("F -> ( E ) | id");
11 System.out.println("Grammar After removing left
recursion");
12 System.out.println("E -> T E'");
13 System.out.println("E' -> + T E' | e");
14 System.out.println("T -> F T'");
15 System.out.println("T' -> * F T' | e");
16 System.out.println("F -> ( E ) | id");
17
18 System.out.println("Enter the string to parse: ");
19 String input = scanner.nextLine(); // Read input from the
user
20 int[] cursor = {0};
21 System.out.println();
22 System.out.println("Input Action");
23 System.out.println("--------------------------------");
24
25 // Call the starting non-terminal E
26 if (E(input, cursor) && cursor[0] == input.length()) { //
If parsing is successful and the cursor has reached the end
27 System.out.println("--------------------------------
");
28 System.out.println("String is successfully parsed");
29 } else {
30 System.out.println("--------------------------------
");
31 System.out.println("Error in parsing String");

15
32 }
33 }
34
35 // Grammar rule: E -> T E'
36 static boolean E(String input, int[] cursor) {
37 System.out.printf("%-16s E -> T E'%n",
input.substring(cursor[0]));
38 if (T(input, cursor)) { // Call non-terminal T
39 if (Edash(input, cursor)) // Call non-terminal E'
40 return true;
41 else
42 return false;
43 } else
44 return false;
45 }
46
47 // Grammar rule: E' -> + T E' | $
48 static boolean Edash(String input, int[] cursor) {
49 if (cursor[0] < input.length() && input.charAt(cursor[0])
== '+') {
50 System.out.printf("%-16s E' -> + T E'%n",
input.substring(cursor[0]));
51 cursor[0]++;
52 if (T(input, cursor)) { // Call non-terminal T
53 if (Edash(input, cursor)) // Call non-terminal E'
54 return true;
55 else
56 return false;
57 } else
58 return false;
59 } else {
60 System.out.printf("%-16s E' -> $%n",
input.substring(cursor[0]));
61 return true;
62 }
63 }
64
65 // Grammar rule: T -> F T'
66 static boolean T(String input, int[] cursor) {
67 System.out.printf("%-16s T -> F T'%n",
input.substring(cursor[0]));
68 if (F(input, cursor)) { // Call non-terminal F
69 if (Tdash(input, cursor)) // Call non-terminal T'
70 return true;
71 else
72 return false;
73 } else
74 return false;
75 }
76
77 // Grammar rule: T' -> * F T' | $
78 static boolean Tdash(String input, int[] cursor) {
79 if (cursor[0] < input.length() && input.charAt(cursor[0])
== '*') {
80 System.out.printf("%-16s T' -> * F T'%n",
input.substring(cursor[0]));
81 cursor[0]++;

16
82 if (F(input, cursor)) { // Call non-terminal F
83 if (Tdash(input, cursor)) // Call non-terminal T'
84 return true;
85 else
86 return false;
87 } else
88 return false;
89 } else {
90 System.out.printf("%-16s T' -> $%n",
input.substring(cursor[0]));
91 return true;
92 }
93 }
94
95 // Grammar rule: F -> ( E ) | i
96 static boolean F(String input, int[] cursor) {
97 if (cursor[0] < input.length() && input.charAt(cursor[0])
== '(') {
98 System.out.printf("%-16s F -> ( E )%n",
input.substring(cursor[0]));
99 cursor[0]++;
100 if (E(input, cursor)) { // Call non-terminal E
101 if (cursor[0] < input.length() &&
input.charAt(cursor[0]) == ')') {
102 cursor[0]++;
103 return true;
104 } else
105 return false;
106 } else
107 return false;
108 } else if (cursor[0] < input.length() &&
input.charAt(cursor[0]) == 'i') {
109 System.out.printf("%-16s F -> i%n",
input.substring(cursor[0]));
110 cursor[0]++;
111 return true;
112 } else
113 return false;
114 }
115 }
116

17
OUTPUT

18
EXPERIMENT 6
AIM: Write a program to implement left factoring.

THEORY:
Left factoring is a process by which the grammar with common prefixes is transformed to make
it useful for Top down parsers.

CODE:

1 import java.util.Scanner;
2
3 public class LeftFactoring {
4 public static String leftFactoredCFG = "";
5 public static String originalCFG;
6 public static String notLeftFactored = "";
7
8 public static boolean isLeftFactoring = false;
9 public static int factorCount = 0;
10
11 public static void main(String[] args) {
12 Scanner scanner = new Scanner(System.in);
13
14 System.out.println("Enter the grammar (one production per
line, use 'epsilon' for empty string, and end with an empty line e.g A
-> aA|bA):");
15 StringBuilder cfgBuilder = new StringBuilder();
16 String line;
17 while (!(line = scanner.nextLine()).isEmpty()) {
18 cfgBuilder.append(line).append("\n");
19 }
20 originalCFG = cfgBuilder.toString();
21
22 System.out.println("The grammar is \n" + originalCFG +
"\n ----------------------------------------------------------");
23 checkFactor(originalCFG);
24 System.out.println("The result of left factoring is \n");
25 System.out.println(notLeftFactored);
26 }
27
28 public static void checkFactor(String cfg) {
29 String[] lines = cfg.split("\n");

19
30 for (String line : lines) {
31 line = line.replaceAll("\\s+", ""); // remove all
white spaces from a line
32
33 String[] productions = line.split("->", 0); //split
the a line at a time into right hand side and left hand side
productions according to -->
34 String lhs = productions[0];
35 String rhs = productions[1];
36 System.out.println(lhs+" -> "+rhs);
37 System.out.println();
38
39 String[] rhsProductions = rhs.split("\\|"); // split
right hand side for productions based on |
40
41 isLeftFactoring = false;
42
43 for (int i = 0; i < rhsProductions.length - 1; i++) {
44 for (int j = i + 1; j < rhsProductions.length;
j++) {
45 if (rhsProductions[i].charAt(0) ==
rhsProductions[j].charAt(0) && (!rhsProductions[i].equals("epsilon")))
{
46 isLeftFactoring = true;
47 }
48 }
49 }
50
51 if (isLeftFactoring) {
52 System.out.println(" This production needs left
factoring!!");
53 System.out.println();
54
55 String commonPrefix = "";
56 commonPrefix = findCommonPrefix(rhsProductions);
57
58 System.out.println("--- common prefix is " +
commonPrefix);
59 System.out.println("-----------------------------
-------------");
60 leftFactorOut(lhs, commonPrefix, rhsProductions);
// to remove left factoring
61 } else {
62 notLeftFactored += line + "\n";
63 System.out.println("This production does not need
left factoring");
64 System.out.println();
65 }
66 }
67 }
68 private static void leftFactorOut(String lhs, String
commonPrefix, String[] rhsProductions) {
69 leftFactoredCFG = lhs + "->";
70 for (String pro : rhsProductions) {
71 if (!pro.startsWith(commonPrefix)) {
72 leftFactoredCFG += pro + "|";
73 }

20
74 }
75 leftFactoredCFG += commonPrefix + "X" + factorCount +
"\n";
76 leftFactoredCFG += "X" + factorCount + "-> ";
77 for (String pro : rhsProductions) {
78 if (pro.startsWith(commonPrefix)) {
79 if (pro.substring(1).isEmpty()) {
80 leftFactoredCFG += "epsilon" + "|";
81 } else {
82 leftFactoredCFG += pro.substring(1) + "|";
83 }
84 }
85 }
86 leftFactoredCFG = leftFactoredCFG.substring(0,
leftFactoredCFG.length() - 1);
87 System.out.println("left factored out \n" +
leftFactoredCFG);
88 if (isLeftFactoring) {
89 factorCount++;
90 checkFactor(leftFactoredCFG);
91 }
92 }
93 public static String findCommonPrefix(String[]
rhsProductions) {
94 String commonPrefix = "";
95 for (int i = 0; i < rhsProductions.length - 1; i++) {
96 for (int j = i + 1; j < rhsProductions.length; j++) {
97 if (rhsProductions[i].charAt(0) ==
rhsProductions[j].charAt(0)) {
98 commonPrefix = rhsProductions[i].charAt(0) +
"";
99 break;
100 }
101 }
102 if (!commonPrefix.isEmpty())
103 break;
104 }
105 return commonPrefix;
106 }
107 }
108

OUTPUT:

21
22
EXPERIMENT 7
AIM: Write a program to convert left recursive grammar to right recursive grammar

THEORY:

A Grammar G (V, T, P, S) is left recursive if it has a production in the form.

A → Aα1 | Aα2|…. |Aαn |β1…..| βm

The above Grammar is left recursive because the left of production is occurring at a first position
on the right side of production. It can eliminate left recursion by replacing the pair of production
with

A → β1A′ |….| βmA′

A → α1A′| α2A′|….| αnA′|ϵ

CODE:

1 import java.util.Scanner;
2
3 public class LeftRecursion {
4 public static String leftRecursionCFG = "";
5 public static String originalCFG;
6 public static String notLeftRecursion= "";
7 public static boolean isLeftRecursion = false;
8
9 public static void main(String[] args) {
10 Scanner scanner = new Scanner(System.in);
11 System.out.println("Enter the grammar (one production per
line, use 'epsilon' for empty string, and end with an empty line e.g A
-> aA|bA):");
12 StringBuilder cfgBuilder = new StringBuilder();
13 String line;
14 while (!(line = scanner.nextLine()).isEmpty()) {
15 cfgBuilder.append(line).append("\n");
16 }
17 originalCFG = cfgBuilder.toString();
18
19 System.out.println("The grammar is \n" + originalCFG +
"\n ----------------------------------------------------------");
20 checkRecursion(originalCFG);
21 System.out.println("The productions after removing left
recursion are: \n");
22 System.out.println(notLeftRecursion);
23 }
24

23
25 public static void checkRecursion(String cfg) {
26 String[] lines = cfg.split("\n");
27 for (String line : lines) {
28 line = line.replaceAll("\\s+", ""); // remove all
white spaces from a line
29
30 String[] productions = line.split("->", 0); //split
the a line at a time into right hand side and left hand side
productions according to -->
31 String lhs = productions[0];
32 String rhs = productions[1];
33 System.out.print(lhs+" -> "+rhs+"\t");
34
35 String[] rhsProductions = rhs.split("\\|"); // split
right hand side for productions based on |
36
37 isLeftRecursion = false;
38
39 int i =0;
40
41 for (i = 0; i < rhsProductions.length ; i++) {
42 if (lhs.equals(""+rhsProductions[i].charAt(0))) {
43 isLeftRecursion = true;
44 break;
45 }
46 }
47
48 if (isLeftRecursion) {
49 System.out.println(" This production has left
recursion!!\n");
50 removeLeftRecursion(lhs, rhsProductions); // to
remove left recursion
51 } else {
52 notLeftRecursion += line + "\n";
53 System.out.println("This production does not have
left recursion\n");
54 }
55 }
56 }
57 private static void removeLeftRecursion(String lhs, String[]
rhsProductions) {
58 leftRecursionCFG = lhs + "->";
59 for (String pro : rhsProductions) {
60 if (!pro.startsWith(lhs)) {
61 leftRecursionCFG += pro +lhs+"'"+ "|";
62 }
63 }
64
leftRecursionCFG=leftRecursionCFG.substring(0,leftRecursionCFG.length(
)-1);
65 leftRecursionCFG +="\n";
66 leftRecursionCFG += lhs+"'"+ "-> ";
67 for (String pro : rhsProductions) {
68 if (pro.startsWith(lhs)) {
69 leftRecursionCFG += pro.substring(1) +
lhs+"'"+"|";
70 }

24
71 }
72 leftRecursionCFG +="epsilon";
73 System.out.println("Production after left recursion on
"+lhs);
74 System.out.println(leftRecursionCFG+"\n");
75
76 if (isLeftRecursion) {
77 checkRecursion(leftRecursionCFG);
78 }
79 }
80 }
81

OUTPUT:

25
EXPERIMENT 8
AIM:Write a program to compute First and Follow.

THEORY:
1) First Set: A set of terminals that are the possible initial symbols of any string derived
from a given non-terminal in a grammar.
Steps to find:
• If X is a terminal, First(X) = {X}.
• If X -> ε is a production rule, add ε to First(X).
• If X -> Y1Y2...Yn is a production rule, add First(Y1Y2...Yn) - {ε} to First(X).
2) Follow Set: A set of terminals that can appear immediately to the right of a given non-
terminal in any sentential form of a grammar.
Steps to find:
• Add $ (the end-of-input marker) to Follow(S), where S is the start symbol.
• If there's a production A -> αBβ, add First(β) - {ε} to Follow(B).
• If there's a production A -> αB or A -> αBβ where β derives ε, add Follow(A) to
Follow(B).

CODE:

1 import java.util.*;
2
3 public class FirstAndFollow {
4 private static String originalCFG;
5 private static Map<String, Set<String>> firstSets = new HashMap<>();
6 private static Map<String, Set<String>> followSets = new HashMap<>();
7
8 public static void main(String[] args) {
9 Scanner scanner = new Scanner(System.in);
10 System.out.println("Enter the grammar (one production per line,
use 'epsilon' for empty string, and end with an empty line e.g A -> aA|bA):");
11 StringBuilder cfgBuilder = new StringBuilder();
12 String line;
13 while (!(line = scanner.nextLine()).isEmpty()) {
14 cfgBuilder.append(line).append("\n");
15 }
16 originalCFG = cfgBuilder.toString();
17
18 System.out.println("The grammar is \n" + originalCFG + "\n ------
----------------------------------------------------");
19
20 // Process the grammar
21 processGrammar();
22 System.out.println("First Set");
23 printSets(firstSets);
24
25 System.out.println("Follow Set");

26
26 printSets(followSets);
27
28 }
29 private static void printSets(Map<String, Set<String>> sets) {
30 for (Map.Entry<String, Set<String>> entry : sets.entrySet()) {
31 String key = entry.getKey();
32 Set<String> value = entry.getValue();
33 System.out.print(key + ": { ");
34 Iterator<String> iterator = value.iterator();
35 while (iterator.hasNext()) {
36 String item = iterator.next();
37 System.out.print(item);
38 if (iterator.hasNext()) {
39 System.out.print(", ");
40 }
41 }
42 System.out.println(" }");
43 }
44 }
45
46
47 private static void processGrammar() {
48 // Step 1: Remove left factoring
49 originalCFG = LeftFactoring.removeLeftFactoring(originalCFG);
50 System.out.println("The productions after left factoring are:
\n");
51 System.out.println(originalCFG);
52
53 // Step 2: Remove left recursion
54 originalCFG = LeftRecursion.removeLeftRecursion(originalCFG);
55 System.out.println("The productions after removing left recursion
are: \n");
56 originalCFG=addSpaces(originalCFG);
57 System.out.println(originalCFG);
58
59 // Step 3: Compute First sets
60 computeFirstSets();
61
62 // Step 4: Compute Follow sets
63 computeFollowSets();
64
65
66 }
67 private static String addSpaces(String cfg) {
68 StringBuilder spacedCFG = new StringBuilder();
69 String[] productions = cfg.split("\n");
70 for (String production : productions) {
71 String[] parts = production.split("->");
72 String nonTerminal = parts[0].trim();
73 String[] symbols = parts[1].trim().split("\\|");
74 StringBuilder spacedProduction = new
StringBuilder(nonTerminal + " -> ");
75 for (String symbol : symbols) {
76 String[] tokens = symbol.trim().split("");
77 for (String token : tokens) {
78 if (!token.isEmpty()) {
79 spacedProduction.append(token).append(" ");
80 }

27
81 }
82 spacedProduction.append("| ");
83 }
84 spacedProduction.deleteCharAt(spacedProduction.length() - 2);
// Remove extra "| "
85 spacedCFG.append(spacedProduction).append("\n");
86 }
87 return spacedCFG.toString();
88 }
89
90 private static void computeFirstSets() {
91 // Split the grammar into productions
92 String[] productions = originalCFG.split("\n");
93
94 // Initialize First sets for each non-terminal
95 for (String production : productions) {
96 String[] parts = production.split("->");
97 String nonTerminal = parts[0].trim();
98 if (!firstSets.containsKey(nonTerminal)) {
99 firstSets.put(nonTerminal, new HashSet<>());
100 }
101 }
102
103 boolean changed;
104 do {
105 changed = false;
106 // Iterate over productions
107 for (String production : productions) {
108 String[] parts = production.split("->");
109 String nonTerminal = parts[0].trim();
110 String[] symbols = parts[1].trim().split("\\|");
111 for (String symbol : symbols) {
112 String[] tokens = symbol.trim().split("\\s+");
113 if (tokens.length == 0) {
114 // Empty production
115 changed |=
firstSets.get(nonTerminal).add("epsilon");
116 } else {
117 // Check if first token is terminal
118 if (Character.isLowerCase(tokens[0].charAt(0))) {
119 changed |=
firstSets.get(nonTerminal).add(tokens[0]);
120 } else {
121 // Non-terminal, add its First set
122 changed |= addFirstSet(nonTerminal, tokens);
123 }
124 }
125 }
126 }
127 } while (changed);
128 }
129
130 private static boolean addFirstSet(String nonTerminal, String[]
symbols) {
131 boolean changed = false;
132 System.out.println(Arrays.toString(symbols));
133 for (String symbol : symbols) {
134 System.out.println(symbol);

28
135 String[] tokens = symbol.trim().split(" "); // Split by
individual characters
136 if (Character.isLowerCase(tokens[0].charAt(0))) {
137 // Terminal, add to First set
138 changed |= firstSets.get(nonTerminal).add(tokens[0]);
139 } else {
140 // Non-terminal, add its First set
141 changed |= addFirstSet(nonTerminal, tokens);
142 if (!firstSets.get(tokens[0]).contains("epsilon")) {
143 break;
144 }
145 }
146 }
147 return changed;
148 }
149
150
151
152
153 private static void computeFollowSets() {
154 // Initialize Follow sets for each non-terminal
155 for (String nonTerminal : firstSets.keySet()) {
156 if (!followSets.containsKey(nonTerminal)) {
157 followSets.put(nonTerminal, new HashSet<>());
158 }
159 }
160
161 // Add $ (end of input) to Follow set of start symbol
162 String startSymbol = originalCFG.split("->")[0].trim();
163 followSets.get(startSymbol).add("$");
164
165 boolean changed;
166 do {
167 changed = false;
168 // Iterate over productions
169 for (String production : originalCFG.split("\n")) {
170 String[] parts = production.split("->");
171 String nonTerminal = parts[0].trim();
172 String[] symbols = parts[1].trim().split("\\|");
173 for (String symbol : symbols) {
174 String[] tokens = symbol.trim().split("\\s+");
175 for (int i = 0; i < tokens.length - 1; i++) {
176 if (!Character.isLowerCase(tokens[i].charAt(0)))
{
177 // Non-terminal
178 changed |= addFollowSet(tokens[i], tokens);
179 }
180 }
181 // Last symbol in production
182 String lastSymbol = tokens[tokens.length - 1];
183 if (!Character.isLowerCase(lastSymbol.charAt(0))) {
184 changed |= addFollowSet(lastSymbol, nonTerminal);
185 }
186 }
187 }
188 } while (changed);
189 }
190

29
191 private static boolean addFollowSet(String nonTerminal, String...
symbols) {
192 boolean changed = false;
193 for (int i = 0; i < symbols.length; i++) {
194 if (symbols[i].equals(nonTerminal)) {
195 if (i < symbols.length - 1) {
196 // Non-terminal followed by another symbol
197 String nextSymbol = symbols[i + 1];
198 if (Character.isLowerCase(nextSymbol.charAt(0))) {
199 // Terminal, add to Follow set
200 changed |=
followSets.get(nonTerminal).add(nextSymbol);
201 } else {
202 // Non-terminal, add its First set (excluding
epsilon) to Follow set
203 Set<String> firstSet = firstSets.get(nextSymbol);
204 for (String terminal : firstSet) {
205 if (!terminal.equals("epsilon")) {
206 changed |=
followSets.get(nonTerminal).add(terminal);
207 }
208 }
209 }
210 }
211 }
212 }
213 return changed;
214 }
215 }

OUTPUT:

30
31
EXPERIMENT 9
AIM:Write a program to construct LL(1) parsing table

THEORY:
An LL(1) parser is a type of top-down parser that reads input from left to right, performs a
leftmost derivation, and uses one token of lookahead to make parsing decisions. It is
characterized by the LL(1) parsing table, which is derived from the grammar's First and Follow
sets.
Steps:

1) Initialize Table: Create an empty LL(1) parsing table with rows for non-terminals and
columns for terminals plus $ (end of input).
2) For each production A -> α:
o If ε is in First(α), for each terminal t in Follow(A), add A -> α to the table entry
[A, t].
o If ε is not in First(α), add A -> α to the table entry [A, t] for each terminal t in
First(α).
o If ε is in First(α) and $ is in Follow(A), add A -> α to the table entry [A, $].
3) Handling ε-productions:
o If A -> ε is a production, for each terminal t in Follow(A), add A -> ε to the
table entry [A, t].
o If $ is in Follow(A), add A -> ε to the table entry [A, $].
4) Conflict Resolution:If there is more than one production listed for a given non-terminal
A and terminal t in the table entry [A, t], there is a conflict. Resolve conflicts by either
restructuring the grammar or using precedence and associativity rules.
5) Check for Ambiguity:Ensure that there are no ambiguities in the parsing table.
Ambiguities may indicate that the grammar is not suitable for LL(1) parsing or that
additional disambiguation rules are needed.
CODE:
1 import java.util.*;
2
3 public class LL1Parser {
4 private Map<String, Map<String, String>> parsingTable;
5 public LL1Parser() {
6 parsingTable = new HashMap<>();
7 }
8 public void constructParsingTable(Map<String, Set<String>>
firstSets, Map<String, Set<String>> followSets, Map<String,
List<String>> productionRules) {
9 for (String nonTerminal : productionRules.keySet()) {
10 Map<String, String> row = new HashMap<>();
11 Set<String> firstSet = firstSets.get(nonTerminal);
12 Set<String> followSet = followSets.get(nonTerminal);
13

32
14 for (String terminal : firstSet) {
15 if (!terminal.equals("epsilon")) {
16 row.put(terminal,
productionRules.get(nonTerminal).get(0)); // Use the first production
rule for the terminal
17 }
18 }
19
20 if (firstSet.contains("epsilon")) {
21 for (String terminal : followSet) {
22 if (!row.containsKey(terminal)) {
23 row.put(terminal, "epsilon");
24 }
25 }
26 }
27 parsingTable.put(nonTerminal, row);
28 }
29 }
30 public void printParsingTable() {
31 System.out.println("LL(1) Parsing Table:");
32 // Print column headers
33 System.out.printf("%-15s", ""); // Empty space for
alignment
34 Set<String> terminals = new HashSet<>();
35 for (Map<String, String> row : parsingTable.values()) {
36 terminals.addAll(row.keySet());
37 }
38 for (String terminal : terminals) {
39 System.out.printf("%-15s", terminal);
40 }
41 System.out.println();
42 // Print table body
43 for (Map.Entry<String, Map<String, String>> entry :
parsingTable.entrySet()) {
44 String nonTerminal = entry.getKey();
45 Map<String, String> row = entry.getValue();
46 System.out.printf("%-15s", nonTerminal);
47 for (String terminal : terminals) {
48 String production = row.get(terminal);
49 if (production != null) {
50 System.out.printf("%-15s", nonTerminal + " ->
" + production);
51 } else {
52 System.out.printf("%-15s", "-");
53 }
54 }
55 System.out.println();
56 }
57 }
58 public static void main(String[] args) {
59 // Sample first sets, follow sets, and production rules
60 Map<String, Set<String>> firstSets = new HashMap<>();
61 Map<String, Set<String>> followSets = new HashMap<>();
62 Map<String, List<String>> productionRules=new
HashMap<>();
63 Scanner scanner = new Scanner(System.in);

33
64 System.out.println("Enter the grammar (one production per
line, use 'epsilon' for empty string, and end with an empty line e.g A
-> aA|bA):");
65 StringBuilder cfgBuilder = new StringBuilder();
66 String line;
67 while (!(line = scanner.nextLine()).isEmpty()) {
68 cfgBuilder.append(line).append("\n");
69 }
70 String grammar = cfgBuilder.toString();
71
72 // Populate first sets, follow sets, and production rules
with your computed values
73 FirstAndFollow ff =new FirstAndFollow(grammar);
74 firstSets=ff.getFirstSets();
75 followSets=ff.getFollowSets();
76 productionRules=ff.getProdRules();
77 System.out.println("First Set:");
78 ff.printSets(firstSets);
79 System.out.println("Follow Set: ");
80 ff.printSets(followSets);
81 // Create LL1Parser instance
82 LL1Parser parser = new LL1Parser();
83
84 // Construct parsing table
85 parser.constructParsingTable(firstSets, followSets,
productionRules);
86
87 // Print parsing table
88 parser.printParsingTable();
89 }
90 }
91

OUTPUT:

34
EXPERIMENT 10
AIM:Write a program to implement non recursive descent predictive parsing.

THEORY:
Non-recursive predictive parsing is a parsing technique used in compiler design and is
based on a predictive parsing table. The predictive parsing table is a 2D table where the rows
represent non-terminals, and the columns represent terminals and $ (end of input). Each cell of the
table contains a production rule to be applied when the non-terminal in the corresponding row is
expanded and the terminal in the corresponding column is the next input symbol.

CODE:
1 import java.util.*;
2
3 public class PredictiveParser{
4 static Map<String, Map<String, String>> parsingTable;
5 public static void main(String[] args) {
6 Map<String, Set<String>> firstSets = new HashMap<>();
7 Map<String, Set<String>> followSets = new HashMap<>();
8 Map<String, List<String>> productionRules=new HashMap<>();
9 Scanner scanner = new Scanner(System.in);
10 System.out.println("Enter the grammar (one production per
line, use 'epsilon' for empty string, and end with an empty line e.g A
-> aA|bA):");
11 StringBuilder cfgBuilder = new StringBuilder();
12 String line;
13 while (!(line = scanner.nextLine()).isEmpty()) {
14 cfgBuilder.append(line).append("\n");
15 }
16 String grammar = cfgBuilder.toString();
17
18 // Populate first sets, follow sets, and production rules
with your computed values
19 FirstAndFollow ff =new FirstAndFollow(grammar);
20 firstSets=ff.getFirstSets();
21 followSets=ff.getFollowSets();
22 productionRules=ff.getProdRules();
23 System.out.println("First Set: ");
24 ff.printSets(firstSets);
25 System.out.println("Follow Set: ");
26 ff.printSets(followSets);
27 // Create LL1Parser instance
28 LL1Parser parser = new LL1Parser();
29
30 // Construct parsing table
31 parsingTable=parser.constructParsingTable(firstSets,
followSets, productionRules);
32 System.out.println("Enter the string to check: ");
33 Scanner sc = new Scanner(System.in);
34 String input=sc.nextLine();
35 predictiveParser(input);
36

35
37 }
38 public static void predictiveParser(String input){
39 System.out.println("Stack"+" "+"Input
Buffer"+" "+"Action");
40 Stack<Character> st=new Stack<>();
41 st.push('$');
42 int index=0;
43 input=input+"$";
44 st.push('A');
45 while(index<input.length()-1){
46 String curr = String.valueOf(st.peek());
47 String inputChar=
String.valueOf(input.charAt(index));
48 String action="Error";
49 if(curr.equals(curr.toUpperCase())){
50 String symbols="";
51
if(parsingTable.get(curr).containsKey(inputChar)){
52
symbols=parsingTable.get(curr).get(inputChar);
53
54 action="replace using "+curr+"-->"+symbols;
55 }
56 else{
57 break;
58 }
59 printStack(st);
60 System.out.println("
"+input.substring(index)+" "+action);
61 if(!symbols.isEmpty()){
62 st.pop();
63 for(int i =symbols.length()-1; i >=0;i--){
64 Character symbol= (Character)
symbols.charAt(i);
65 if(symbol!=' '){
66 st.push(symbol);
67 }
68 }
69 }
70 }
71 else{
72 if(st.peek().equals(input.charAt(index))){
73 if(st.peek()=='$')
74 break;
75 action="Pop";
76 printStack(st);
77 System.out.println("
"+input.substring(index)+" "+action);
78
79 st.pop();
80 index++;
81 }
82 else{
83 break;
84 }
85 }
86 }

36
87 if(st.peek()==input.charAt(index)){
88 System.out.println("$"+" "+"$"+"
"+"Accept");
89 }
90 else{
91 printStack(st);
92 System.out.println("
"+input.substring(index)+" "+"REject");
93 }
94
95
96 }
97 public static void printStack(Stack<Character> stack) {
98 for (Character character : stack) {
99 System.out.print(character);
100 }
101 }
102 }
103

OUTPUT:

37
EXPERIMENT-11

AIM: Write a program to implement an error handler.


THEORY:
In compiler design, error handling is essential for ensuring the correctness and reliability of the
compilation process. Errors can occur at various stages, including lexical analysis, syntax analysis,
semantic analysis, and code generation.
Types of Errors:
1. Lexical Errors: Arise during lexical analysis due to invalid characters or misspelled
keywords.
2. Syntax Errors: Result from violations of language grammar rules during parsing.
3. Semantic Errors: Involve misuse of language constructs, type mismatches, or undeclared
variables.
4. Runtime Errors: Occur during program execution, such as division by zero or null pointer
dereference.
Techniques:
1. Error Detection: Compiler examines input code to identify deviations from language
specifications.
2. Error Reporting: Generates clear and informative error messages describing the nature
and location of errors.
3. Error Recovery: Attempts to continue compilation after detecting errors, often by
skipping erroneous code segments.
4. Error Prevention: Aims to prevent errors through robust language specifications and
static analysis tools.

CODE:
1 import java.util.ArrayList;
2 import java.util.List;
3 import java.util.Scanner;
4
5 class ErrorHandler {
6 private List<String> errors = new ArrayList<>();
7 public void handleError(String message, int lineNumber) {
8 errors.add("Error on line " + lineNumber + ": " + message);
9 }
10 public boolean hasErrors() {
11 return !errors.isEmpty();
12 }
13 public List<String> getErrors() {
14 return errors;
15 }
16 }
17
18 public class Main {
19 public static void main(String[] args) {
20 ErrorHandler errorHandler = new ErrorHandler();
21 System.out.println("Enter your code (lines terminated by
';'):");

38
22 Scanner scanner = new Scanner(System.in);
23 StringBuilder codeBuilder = new StringBuilder();
24 int lineNumber = 1;
25 while (true) {
26 String line = scanner.nextLine();
27 if (line.equals("")) break; // Exit loop on empty
line
28 codeBuilder.append(line).append('\n');
29 lineNumber++;
30 }
31 scanner.close();
32
33 String[] lines = codeBuilder.toString().split("\n");
34 lineNumber=1;
35 for (String line : lines) {
36 if (!line.isEmpty() && !line.contains(";")) {
37 errorHandler.handleError("Missing semicolon",
lineNumber);
38 }
39 lineNumber++;
40 }
41 if (errorHandler.hasErrors()) {
42 System.out.println("Compilation errors:");
43 for (String error : errorHandler.getErrors()) {
44 System.out.println(error);
45 }
46 } else {
47 System.out.println("Compilation successful!");
48 }
49 }
50 }

OUTPUT:

39
EXPERIMENT 12
AIM:Write a program to implement one pass compiler.
THEORY:
○ One-pass compilers process source code sequentially in a single pass.
○ They generate machine code or intermediate code during this pass.
○ Forward references, such as function or variable declarations, are handled using
techniques like symbol tables and forward declarations.
○ Limited optimization is performed, focusing on simple optimizations like constant
folding and dead code elimination.
○ One-pass compilers are memory-efficient as they don't need to store intermediate
representations of the entire source code.
○ They are suitable for small projects or languages with simple syntax and semantics.
○ One-pass compilers may lack advanced optimization and robust error handling compared
to multi-pass compilers..

CODE:
1 import java.util.*;
2 enum TokenType {
3 KEYWORD,
4 IDENTIFIER,
5 OPERATOR,
6 LITERAL,
7 DELIMITER,
8 COMMENT
9 }
10
11
12 public class OnePassCompiler {
13 public static void main(String[] args) {
14 Scanner scanner = new Scanner(System.in);
15 System.out.println("Enter your code:");
16 String input = scanner.nextLine();
17
18 // Lexical Analysis
19 List<Token> tokens = lexer(input);
20
21 // Syntax Analysis
22 if (parser(tokens)) {
23 // Semantic Analysis
24 if (semanticAnalyzer(tokens)) {
25 // Code Generation
26 codeGenerator(tokens);
27 System.out.println("Compilation successful!");
28 } else {
29 System.out.println("Semantic errors found.
Compilation failed.");
30 }
31 } else {
32 System.out.println("Syntax errors found. Compilation
failed.");

40
33 }
34 }
35
36 // Lexical Analysis: Convert input code into tokens
37 private static List<Token> lexer(String input) {
38 List<Token> tokens = new ArrayList<>();
39 System.out.println("Performing Lexical Analysis...");
40 System.out.println("Lexical Analysis done!!");
41 return tokens;
42 }
43
44 // Syntax Analysis: Check if the tokens form a valid syntax
45 private static boolean parser(List<Token> tokens) {
46 System.out.println("Parsing...");
47 System.out.println("Successfully parsed!!");
48 return true;
49 }
50
51 // Semantic Analysis: Analyze the meaning of the code
52 private static boolean semanticAnalyzer(List<Token> tokens) {
53 System.out.println("Performing semantic Analysis...");
54 System.out.println("Semantic Analysis done!!");
55 return true;
56 }
57
58 // Code Generation: Generate machine code or intermediate
code
59 private static void codeGenerator(List<Token> tokens) {
60 System.out.println("Generating Three Address Code...");
61 System.out.println("Three Address Code generated!!");
62 System.out.println("Code optimized!!");
63 }
64 }
65
66 // Token class to represent tokens generated during lexical
analysis
67 class Token {
68 TokenType type;
69 String value;
70
71 public Token(TokenType type, String value) {
72 this.type = type;
73 this.value = value;
74 }
75 }
76
77

OUTPUT:

41
42

You might also like