-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCfgLeftRecElim.java
More file actions
186 lines (145 loc) · 5 KB
/
CfgLeftRecElim.java
File metadata and controls
186 lines (145 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package csen1002.main.task5;
import java.util.ArrayList;
import java.util.Hashtable;
/**
* Write your info here
*
* @name Tarteel Elattar
* @id 49-2019
* @labNumber 17
*/
public class CfgLeftRecElim {
Hashtable<String, ArrayList<String>> contextFreeGrammar = new Hashtable<String, ArrayList<String>>();
String[] originalVariables;
String[] terminalArray;
String variables = "";
String terminals = "";
ArrayList<String> replacement = new ArrayList<String>();
ArrayList<String> terminal = new ArrayList<String>();
/**
* Constructs a Context Free Grammar
*
* @param cfg A formatted string representation of the CFG. The string
* representation follows the one in the task description
*/
public CfgLeftRecElim(String cfg) {
// start parsing the input string
String[] splitted = cfg.split("#");
variables = splitted[0];
terminals = splitted[1];
String[] grammar = splitted[2].split(";");
originalVariables = variables.split(";");
String variable;
ArrayList<String> terminal;
String[] var;
for (String g : grammar) {
var = g.split("/");
variable = var[0];
terminalArray = g.split("/")[1].split(",");
terminal = new ArrayList<String>();
for (String te : terminalArray)
terminal.add(te);
contextFreeGrammar.put(variable, terminal);
}
}
/**
* @return Returns a formatted string representation of the CFG. The string
* representation follows the one in the task description
*/
@Override
public String toString() {
for (String var : originalVariables) {
if (contextFreeGrammar.keySet().contains(var + "'"))
variables += ";" + var + "'";
}
StringBuilder result = new StringBuilder(variables + "#" + terminals + "#");
for (String v : variables.split(";")) {
result.append(v + "/");
for (String terminal : contextFreeGrammar.get(v))
result.append(terminal + ",");
result.deleteCharAt(result.length() - 1);
result.append(";");
}
result.deleteCharAt(result.length() - 1);
return result.toString();
}
/**
* Eliminates Left Recursion from the grammar
*/
public void eliminateImmediateLeftRec(String currentKey) {
Hashtable<String, ArrayList<String>> additionalRules = new Hashtable<String, ArrayList<String>>();
String newVariable = "";
boolean isLeftRec;
replacement = new ArrayList<String>();
terminal = new ArrayList<String>();
isLeftRec = false;
terminal = contextFreeGrammar.get(currentKey);
// check the rules. does any of them start with the variable itself?
for (String t : terminal) {
if (!(t.charAt(0) + "").equals(currentKey))
continue;
isLeftRec = true;
newVariable = currentKey + "'";
replacement.add(t.substring(1) + newVariable);
}
if (isLeftRec) {
// add or epsilon to the introduced rule
replacement.add("e");
// remove the immediate left recursion from the original rule
terminal.removeIf(s -> s.charAt(0) == currentKey.charAt(0));
// add the new variable to the end of each terminal
for (int i = 0; i < terminal.size(); i++)
terminal.set(i, terminal.get(i) + newVariable);
// System.out.println(terminal);
additionalRules.put(newVariable, new ArrayList<String>(replacement));
}
// to avoid concurrent modification errors, pour all the additional rules to the
// original hash table
contextFreeGrammar.putAll(additionalRules);
}
public void eliminateLeftRecursion() {
Hashtable<String, ArrayList<String>> replace = new Hashtable<String, ArrayList<String>>();
replacement = new ArrayList<String>();
terminal = new ArrayList<String>();
String modified = "";
int insertIndex;
boolean change = false;
//eliminate immediate left recursion on the start variable
eliminateImmediateLeftRec("S");
// loop on the grammar hash table
while (!change) {
// loop on all the original variables and make sure there is no general left
// recursion
// this is done by making sure no rule starts with a variable that was defined
// before it..
for (int i = 1; i < originalVariables.length; i++) {
terminal = contextFreeGrammar.get(originalVariables[i]);
for (int j = 0; j < i; j++) {
for (String t : terminal) {
if (!(t.charAt(0) + "").equals(originalVariables[j]))
continue;
replacement.clear();
for (String s : contextFreeGrammar.get(originalVariables[j])) {
modified = t.replaceFirst(originalVariables[j], s);
replacement.add(modified);
}
replace.put(t, new ArrayList<String>(replacement));
}
// insert in the positions specified in the lecture
for (String s : replace.keySet()) {
insertIndex = terminal.indexOf(s);
terminal.remove(s);
terminal.addAll(insertIndex, replace.get(s));
change = true;
}
replace.clear();
}
eliminateImmediateLeftRec(originalVariables[i]);
}
if (change)
change = false;
else
break;
}
}
}