1 using System;
2 using System.Lex;
3 using RexTokens;
4
5 namespace System.RegularExpressions
6 {
7 public Nfa ParseRegularExpressionPattern(RexLexer& lexer, Context& context)
8 {
9 lexer.SetFlag(LexerFlags.farthestError);
10 ++lexer;
11 Nfa nfa;
12 bool matched = ParseAlternative(lexer, context, nfa);
13 if (!matched || *lexer != END)
14 {
15 lexer.ThrowFarthestError();
16 }
17 return nfa;
18 }
19
20 public bool ParseAlternative(RexLexer& lexer, Context& context, Nfa& nfa)
21 {
22 long save = lexer.GetPos();
23 if (ParseCatenation(lexer, context, nfa))
24 {
25 while (*lexer == ALT)
26 {
27 ++lexer;
28 Nfa right;
29 if (ParseCatenation(lexer, context, right))
30 {
31 nfa = Alt(context, nfa, right);
32 }
33 else
34 {
35 lexer.SetPos(save);
36 return false;
37 }
38 }
39 return true;
40 }
41 lexer.SetPos(save);
42 return false;
43 }
44
45 public bool ParseCatenation(RexLexer& lexer, Context& context, Nfa& nfa)
46 {
47 long save = lexer.GetPos();
48 if (ParseRepetition(lexer, context, nfa))
49 {
50 Nfa right;
51 while (ParseRepetition(lexer, context, right))
52 {
53 nfa = Cat(context, nfa, right);
54 right = Nfa();
55 }
56 return true;
57 }
58 lexer.SetPos(save);
59 return false;
60 }
61
62 public bool ParseRepetition(RexLexer& lexer, Context& context, Nfa& nfa)
63 {
64 long save = lexer.GetPos();
65 if (ParsePrimary(lexer, context, nfa))
66 {
67 switch (*lexer)
68 {
69 case STAR:
70 {
71 ++lexer;
72 nfa = Kleene(context, nfa);
73 return true;
74 }
75 case PLUS:
76 {
77 ++lexer;
78 nfa = Pos(context, nfa);
79 return true;
80 }
81 case QUEST:
82 {
83 ++lexer;
84 nfa = Opt(context, nfa);
85 return true;
86 }
87 }
88 return true;
89 }
90 lexer.SetPos(save);
91 return false;
92 }
93
94 public bool ParsePrimary(RexLexer& lexer, Context& context, Nfa& nfa)
95 {
96 long save = lexer.GetPos();
97 switch (*lexer)
98 {
99 case LPAREN:
100 {
101 ++lexer;
102 if (ParseAlternative(lexer, context, nfa))
103 {
104 if (*lexer == RPAREN)
105 {
106 ++lexer;
107 return true;
108 }
109 }
110 break;
111 }
112 case ESCAPE:
113 {
114 long pos = lexer.GetPos();
115 ++lexer;
116 uchar escape = MakeEscapeValue(lexer.FileName(), lexer.GetToken(pos));
117 nfa = MakeNfa(context, context.MakeChar(escape));
118 return true;
119 }
120 case INVERSE:
121 {
122 ++lexer;
123 nfa = MakeNfa(context, context.MakeChar('^'));
124 return true;
125 }
126 case MINUS:
127 {
128 ++lexer;
129 nfa = MakeNfa(context, context.MakeChar('-'));
130 return true;
131 }
132 case CHAR:
133 {
134 long pos = lexer.GetPos();
135 ++lexer;
136 uchar ch = lexer.GetUChar(pos);
137 Symbol* symbol = context.MakeChar(ch);
138 nfa = MakeNfa(context, symbol);
139 return true;
140 }
141 case DOT:
142 {
143 ++lexer;
144 nfa = MakeNfa(context, context.MakeAny());
145 return true;
146 }
147 default:
148 {
149 Class* cls = null;
150 if (ParseClass(lexer, context, cls))
151 {
152 nfa = MakeNfa(context, cls);
153 return true;
154 }
155 break;
156 }
157 }
158 lexer.SetPos(save);
159 return false;
160 }
161
162 public bool ParseClass(RexLexer& lexer, Context& context, Class*& cls)
163 {
164 long save = lexer.GetPos();
165 if (*lexer == LBRACKET)
166 {
167 ++lexer;
168 cls = context.MakeClass();
169 if (*lexer == INVERSE)
170 {
171 Class* invCls = cls;
172 invCls->SetInverse();
173 ++lexer;
174 }
175 Symbol* symbol = null;
176 while (ParseRange(lexer, context, symbol))
177 {
178 Class* symCls = cls;
179 symCls->AddSymbol(symbol);
180 symbol = null;
181 }
182 if (*lexer == RBRACKET)
183 {
184 ++lexer;
185 return true;
186 }
187 }
188 lexer.SetPos(save);
189 return false;
190 }
191
192 public bool ParseRange(RexLexer& lexer, Context& context, Symbol*& symbol)
193 {
194 long save = lexer.GetPos();
195 uchar s;
196 if (ParseChar(lexer, context, s))
197 {
198 if (*lexer == MINUS)
199 {
200 ++lexer;
201 uchar e;
202 if (ParseChar(lexer, context, e))
203 {
204 symbol = context.MakeRange(s, e);
205 return true;
206 }
207 }
208 else
209 {
210 symbol = context.MakeChar(s);
211 return true;
212 }
213 }
214 lexer.SetPos(save);
215 return false;
216 }
217
218 public bool ParseChar(RexLexer& lexer, Context& context, uchar& ch)
219 {
220 long save = lexer.GetPos();
221 switch (*lexer)
222 {
223 case LPAREN:
224 {
225 ++lexer;
226 ch = '(';
227 return true;
228 }
229 case RPAREN:
230 {
231 ++lexer;
232 ch = ')';
233 return true;
234 }
235 case LBRACKET:
236 {
237 ++lexer;
238 ch = '[';
239 return true;
240 }
241 case ALT:
242 {
243 ++lexer;
244 ch = '|';
245 return true;
246 }
247 case STAR:
248 {
249 ++lexer;
250 ch = '*';
251 return true;
252 }
253 case PLUS:
254 {
255 ++lexer;
256 ch = '+';
257 return true;
258 }
259 case QUEST:
260 {
261 ++lexer;
262 ch = '?';
263 return true;
264 }
265 case DOT:
266 {
267 ++lexer;
268 ch = '.';
269 return true;
270 }
271 case ESCAPE:
272 {
273 long pos = lexer.GetPos();
274 ++lexer;
275 ch = MakeEscapeValue(lexer.FileName(), lexer.GetToken(pos));
276 return true;
277 }
278 case INVERSE:
279 {
280 ++lexer;
281 ch = '^';
282 return true;
283 }
284 case MINUS:
285 {
286 ++lexer;
287 ch = '-';
288 return true;
289 }
290 case CHAR:
291 {
292 long pos = lexer.GetPos();
293 ++lexer;
294 ch = lexer.GetUChar(pos);
295 return true;
296 }
297 }
298 lexer.SetPos(save);
299 return false;
300 }
301 }