STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
Lexer.cs
Go to the documentation of this file.
1 /*
2  * Created by SharpDevelop.
3  * User: lextm
4  * Date: 2008/5/17
5  * Time: 16:50
6  *
7  * To change this template use Tools | Options | Coding | Edit Standard Headers.
8  */
9 
10 using System;
11 using System.Collections.Generic;
12 using System.IO;
13 using System.Text;
15 
16 namespace Lextm.SharpSnmpLib.Mib
17 {
21  public sealed class Lexer
22  {
23  private readonly SymbolList _symbols = new SymbolList();
24 
25  public Lexer(string file)
26  : this(file, new StreamReader(file))
27  {
28  }
29 
30  public Lexer(string file, TextReader stream)
31  {
32  this.Parse(file, stream);
33  }
34 
35 
37  {
38  return _symbols.GetSymbolEnumerator();
39  }
40 
41 
42  #region Parsing of MIB File
43 
44  private class ParseParams
45  {
46  public string File;
47  public StringBuilder Temp = new StringBuilder();
48  public bool StringSection = false;
49  public bool AssignSection = false;
50  public bool AssignAhead = false;
51  public bool DotSection = false;
52 
53  }
54 
60  private void Parse(string file, TextReader stream)
61  {
62  if (stream == null)
63  {
64  throw new ArgumentNullException("stream");
65  }
66 
67  ParseParams pp = new ParseParams();
68  pp.File = file;
69 
70  string line;
71  int row = 0;
72  while ((line = stream.ReadLine()) != null)
73  {
74  if (!pp.StringSection && line.TrimStart().StartsWith("--", StringComparison.Ordinal))
75  {
76  row++;
77  continue; // commented line
78  }
79 
80  ParseLine(pp, line, row);
81  row++;
82  }
83  }
84 
85  private void ParseLine(ParseParams pp, string line, int row)
86  {
87  line = line + "\n";
88  int count = line.Length;
89  for (int i = 0; i < count; i++)
90  {
91  char current = line[i];
92  bool moveNext = Parse(pp, current, row, i);
93  if (moveNext)
94  {
95  break;
96  }
97  }
98  }
99 
100  private bool Parse(ParseParams pp, char current, int row, int column)
101  {
102  switch (current)
103  {
104  case '\n':
105  case '{':
106  case '}':
107  case '(':
108  case ')':
109  case '[':
110  case ']':
111  case ';':
112  case ',':
113  case '|':
114  if (!pp.StringSection)
115  {
116  bool moveNext = ParseLastSymbol(pp, row, column);
117  if (moveNext)
118  {
119  _symbols.Add(CreateSpecialSymbol(pp.File, '\n', row, column));
120  return true;
121  }
122 
123  _symbols.Add(CreateSpecialSymbol(pp.File, current, row, column));
124  return false;
125  }
126 
127  break;
128  case '"':
129  pp.StringSection = !pp.StringSection;
130  break;
131  case '\r':
132  return false;
133  default:
134  if ((int)current == 0x1A)
135  {
136  // IMPORTANT: ignore invisible characters such as SUB.
137  return false;
138  }
139 
140  if (Char.IsWhiteSpace(current) && !pp.AssignSection && !pp.StringSection)
141  {
142  bool moveNext = ParseLastSymbol(pp, row, column);
143  if (moveNext)
144  {
145  _symbols.Add(CreateSpecialSymbol(pp.File, '\n', row, column));
146  return true;
147  }
148 
149  return false;
150  }
151 
152  if (pp.AssignAhead)
153  {
154  pp.AssignAhead = false;
155  ParseLastSymbol(pp, row, column);
156  break;
157  }
158 
159  if (pp.DotSection && current != '.')
160  {
161  ParseLastSymbol(pp, row, column);
162  pp.DotSection = false;
163  }
164 
165  if (current == '.' && !pp.StringSection)
166  {
167  if (!pp.DotSection)
168  {
169  ParseLastSymbol(pp, row, column);
170  pp.DotSection = true;
171  }
172  }
173 
174  if (current == ':' && !pp.StringSection)
175  {
176  if (!pp.AssignSection)
177  {
178  ParseLastSymbol(pp, row, column);
179  }
180 
181  pp.AssignSection = true;
182  }
183 
184  if (current == '=' && !pp.StringSection)
185  {
186  pp.AssignSection = false;
187  pp.AssignAhead = true;
188  }
189 
190  break;
191  }
192 
193  pp.Temp.Append(current);
194  return false;
195  }
196 
197  private bool ParseLastSymbol(ParseParams pp, int row, int column)
198  {
199  if (pp.Temp.Length > 0)
200  {
201  Symbol s = new Symbol(pp.File, pp.Temp.ToString(), row, column);
202 
203  pp.Temp.Length = 0;
204 
205  if (s.ToString().StartsWith(Symbol.Comment.ToString()))
206  {
207  // ignore the rest symbols on this line because they are in comment.
208  return true;
209  }
210 
211  _symbols.Add(s);
212  }
213 
214  return false;
215  }
216 
217  private static Symbol CreateSpecialSymbol(string file, char value, int row, int column)
218  {
219  string str;
220  switch (value)
221  {
222  case '\n':
223  str = Environment.NewLine;
224  break;
225  case '{':
226  str = "{";
227  break;
228  case '}':
229  str = "}";
230  break;
231  case '(':
232  str = "(";
233  break;
234  case ')':
235  str = ")";
236  break;
237  case '[':
238  str = "[";
239  break;
240  case ']':
241  str = "]";
242  break;
243  case ';':
244  str = ";";
245  break;
246  case ',':
247  str = ",";
248  break;
249  case '|':
250  str = "|";
251  break;
252  default:
253  throw new ArgumentException("value is not a special character");
254  }
255 
256  return new Symbol(file, str, row, column);
257  }
258 
259  #endregion
260 
261  #region Static Parse Helper
262 
263  public static ITypeAssignment ParseBasicTypeDef(IModule module, string name, ISymbolEnumerator symbols, bool isMacroSyntax = false)
264  {
265  Symbol current = symbols.NextNonEOLSymbol();
266 
267  if (current == Symbol.Bits)
268  {
269  return new BitsType(module, name, symbols);
270  }
271  if (IntegerType.IsIntegerType(current))
272  {
273  return new IntegerType(module, name, current, symbols);
274  }
275  if (UnsignedType.IsUnsignedType(current))
276  {
277  return new UnsignedType(module, name, current, symbols);
278  }
279  if (current == Symbol.Opaque)
280  {
281  return new OpaqueType(module, name, symbols);
282  }
283  if (current == Symbol.IpAddress)
284  {
285  return new IpAddressType(module, name, symbols);
286  }
287  if (current == Symbol.TextualConvention)
288  {
289  return new TextualConvention(module, name, symbols);
290  }
291  if (current == Symbol.Octet)
292  {
293  Symbol next = symbols.NextNonEOLSymbol();
294 
295  if (next == Symbol.String)
296  {
297  return new OctetStringType(module, name, symbols);
298  }
299 
300  symbols.PutBack(next);
301  }
302  if (current == Symbol.Object)
303  {
304  Symbol next = symbols.NextNonEOLSymbol();
305 
306  if (next == Symbol.Identifier)
307  {
308  return new ObjectIdentifierType(module, name, symbols);
309  }
310 
311  symbols.PutBack(next);
312  }
313  if (current == Symbol.Sequence)
314  {
315  Symbol next = symbols.NextNonEOLSymbol();
316 
317  if (next == Symbol.Of)
318  {
319  return new SequenceOf(module, name, symbols);
320  }
321  else
322  {
323  symbols.PutBack(next);
324  return new Sequence(module, name, symbols);
325  }
326  }
327  if (current == Symbol.Choice)
328  {
329  return new Choice(module, name, symbols);
330  }
331 
332 
333  return new TypeAssignment(module, name, current, symbols, isMacroSyntax);
334  }
335 
336  public static void ParseOidValue(ISymbolEnumerator symbols, out string parent, out uint value)
337  {
338  parent = null;
339  value = 0;
340 
341  Symbol current = symbols.NextNonEOLSymbol();
342  current.Expect(Symbol.OpenBracket);
343 
344  Symbol previous = null;
345  StringBuilder longParent = new StringBuilder();
346 
347  current = symbols.NextNonEOLSymbol();
348  longParent.Append(current);
349 
350  while ((current = symbols.NextNonEOLSymbol()) != null)
351  {
352  bool succeeded;
353 
354  if (current == Symbol.OpenParentheses)
355  {
356  longParent.Append(current);
357 
358  current = symbols.NextNonEOLSymbol();
359  succeeded = UInt32.TryParse(current.ToString(), out value);
360  current.Assert(succeeded, "not a decimal");
361  longParent.Append(current);
362  current = symbols.NextNonEOLSymbol();
363  current.Expect(Symbol.CloseParentheses);
364  longParent.Append(current);
365  continue;
366  }
367 
368  if (current == Symbol.CloseBracket)
369  {
370  parent = longParent.ToString();
371  return;
372  }
373 
374  succeeded = UInt32.TryParse(current.ToString(), out value);
375  if (succeeded)
376  {
377  // numerical way
378  while ((current = symbols.NextNonEOLSymbol()) != Symbol.CloseBracket)
379  {
380  longParent.Append(".").Append(value);
381  succeeded = UInt32.TryParse(current.ToString(), out value);
382  current.Assert(succeeded, "not a decimal");
383  }
384 
385  current.Expect(Symbol.CloseBracket);
386  parent = longParent.ToString();
387  return;
388  }
389 
390  longParent.Append(".");
391  longParent.Append(current);
392  current = symbols.NextNonEOLSymbol();
393  current.Expect(Symbol.OpenParentheses);
394  longParent.Append(current);
395  current = symbols.NextNonEOLSymbol();
396  succeeded = UInt32.TryParse(current.ToString(), out value);
397  current.Assert(succeeded, "not a decimal");
398  longParent.Append(current);
399  current = symbols.NextNonEOLSymbol();
400  current.Expect(Symbol.CloseParentheses);
401  longParent.Append(current);
402  previous = current;
403  }
404 
405  throw MibException.Create("end of file reached", previous);
406  }
407 
408 
410  {
411  ValueRanges result = new ValueRanges();
412 
413  Symbol startSymbol = symbols.NextNonEOLSymbol();
414  Symbol current = startSymbol;
415  current.Expect(Symbol.OpenParentheses);
416 
417  while (current != Symbol.CloseParentheses)
418  {
419  Symbol value1Symbol = symbols.NextNonEOLSymbol();
420 
421  if ((value1Symbol == Symbol.Size) && !result.IsSizeDeclaration)
422  {
423  result.IsSizeDeclaration = true;
424  symbols.NextNonEOLSymbol().Expect(Symbol.OpenParentheses);
425  continue;
426  }
427 
428  // check for valid number
429  Int64? value1 = DecodeNumber(value1Symbol);
430  if (!value1.HasValue)
431  {
432  value1Symbol.Assert(false, "Invalid range declaration!");
433  }
434 
435  // process next symbol
436  ValueRange range;
437  current = symbols.NextNonEOLSymbol();
438 
439  if (current == Symbol.DoubleDot)
440  {
441  // its a continous range
442  Symbol value2Symbol = symbols.NextNonEOLSymbol();
443  Int64? value2 = DecodeNumber(value2Symbol);
444  value2Symbol.Assert(value2.HasValue && (value2.Value >= value1.Value), "Invalid range declaration!");
445 
446  if (value2.Value == value1.Value)
447  {
448  range = new ValueRange(value1.Value, null);
449  }
450  else
451  {
452  range = new ValueRange(value1.Value, value2.Value);
453  }
454 
455  current = symbols.NextNonEOLSymbol();
456  }
457  else
458  {
459  // its a single number
460  range = new ValueRange(value1.Value, null);
461  }
462 
463  // validate range
464  if (result.IsSizeDeclaration)
465  {
466  value1Symbol.Assert(range.Start >= 0, "Invalid range declaration! Size must be greater than 0");
467  }
468 
469  result.Add(range);
470 
471  // check next symbol
472  current.Expect(Symbol.Pipe, Symbol.CloseParentheses);
473  }
474 
475  if (result.IsSizeDeclaration)
476  {
477  current = symbols.NextNonEOLSymbol();
478  current.Expect(Symbol.CloseParentheses);
479  }
480 
481  // validate ranges in between
482  for (int i=0; i<result.Count; i++)
483  {
484  for (int k=i+1; k<result.Count; k++)
485  {
486  startSymbol.Assert(!result[i].IntersectsWith(result[k]), "Invalid range declaration! Overlapping of ranges!");
487  }
488  }
489 
490  return result;
491  }
492 
493  public static Int64? DecodeNumber(Symbol number)
494  {
495  Int64 result;
496  string numString = (number != null) ? number.ToString() : null;
497 
498  if (!String.IsNullOrEmpty(numString))
499  {
500  if (numString.StartsWith("'") && (numString.Length > 3))
501  {
502  // search second apostrophe
503  int end = numString.IndexOf('\'', 1);
504  if (end == (numString.Length - 2))
505  {
506  try
507  {
508  switch (numString[numString.Length - 1])
509  {
510  case 'b':
511  case 'B':
512  result = Convert.ToInt64(numString.Substring(1, numString.Length - 3), 2);
513  return result;
514  case 'h':
515  case 'H':
516  result = Convert.ToInt64(numString.Substring(1, numString.Length - 3), 16);
517  return result;
518  }
519  }
520  catch
521  {
522  }
523  }
524  }
525  else if (Int64.TryParse(numString, out result))
526  {
527  return result;
528  }
529  }
530 
531  return null;
532  }
533 
535  {
536  Symbol current = symbols.NextNonEOLSymbol();
537  current.Expect(Symbol.OpenBracket);
538 
539  ValueMap map = new ValueMap();
540  do
541  {
542  current = symbols.NextNonEOLSymbol();
543  string identifier = current.ToString();
544 
545  current = symbols.NextNonEOLSymbol();
546  current.Expect(Symbol.OpenParentheses);
547 
548  current = symbols.NextNonEOLSymbol();
549  Int64 enumValue;
550  if (Int64.TryParse(current.ToString(), out enumValue))
551  {
552  try
553  {
554  // Have to include the number as it seems repeated identifiers are allowed ??
555  map.Add(enumValue, String.Format("{0}({1})", identifier, enumValue));
556  }
557  catch (ArgumentException ex)
558  {
559  current.Assert(false, ex.Message);
560  }
561  }
562  else
563  {
564  // Need to get "DefinedValue".
565  }
566 
567  current = symbols.NextNonEOLSymbol();
568  current.Expect(Symbol.CloseParentheses);
569 
570  current = symbols.NextNonEOLSymbol();
571  } while (current == Symbol.Comma);
572 
573  current.Expect(Symbol.CloseBracket);
574 
575  return map;
576  }
577 
578  #endregion
579 
580  }
581 }
static readonly Symbol Pipe
Definition: Symbol.cs:219
static readonly Symbol IpAddress
Definition: Symbol.cs:230
The CHOICE type represents a list of alternatives..
Definition: Choice.cs:15
static readonly Symbol TextualConvention
Definition: Symbol.cs:206
The SEQUENCE type represents a set of specified types. This is roughtly analogous to a ...
Definition: Sequence.cs:16
MIB Module interface.
Definition: IModule.cs:36
static void ParseOidValue(ISymbolEnumerator symbols, out string parent, out uint value)
Definition: Lexer.cs:336
static readonly Symbol Object
Definition: Symbol.cs:182
static ValueRanges DecodeRanges(ISymbolEnumerator symbols)
Definition: Lexer.cs:409
static readonly Symbol Octet
Definition: Symbol.cs:209
static readonly Symbol Comma
Definition: Symbol.cs:205
Lexer(string file)
Definition: Lexer.cs:25
static readonly Symbol DoubleDot
Definition: Symbol.cs:218
Description of MibException.
Definition: MibException.cs:24
static readonly Symbol Bits
Definition: Symbol.cs:208
ISymbolEnumerator GetEnumerator()
Definition: Lexer.cs:36
static readonly Symbol Opaque
Definition: Symbol.cs:234
static Int64 DecodeNumber(Symbol number)
Definition: Lexer.cs:493
static ValueMap DecodeEnumerations(ISymbolEnumerator symbols)
Definition: Lexer.cs:534
The INTEGER type represents a list of alternatives, or a range of numbers.. Includes Integer32 as it&#39;...
Definition: IntegerType.cs:25
static readonly Symbol Identifier
Definition: Symbol.cs:183
Lexer(string file, TextReader stream)
Definition: Lexer.cs:30
static readonly Symbol OpenParentheses
Definition: Symbol.cs:211
static readonly Symbol OpenBracket
Definition: Symbol.cs:185
Lexer class that parses MIB files into symbol list.
Definition: Lexer.cs:21
static readonly Symbol Comment
Definition: Symbol.cs:187
static MibException Create(string message, Symbol symbol)
Creates a MibException with a specific Symbol.
Definition: MibException.cs:90
static readonly Symbol Sequence
Definition: Symbol.cs:196
static readonly Symbol Of
Definition: Symbol.cs:227
static readonly Symbol Size
Definition: Symbol.cs:220
static readonly Symbol CloseParentheses
Definition: Symbol.cs:212
static ITypeAssignment ParseBasicTypeDef(IModule module, string name, ISymbolEnumerator symbols, bool isMacroSyntax=false)
Definition: Lexer.cs:263
static readonly Symbol CloseBracket
Definition: Symbol.cs:186
Description of Symbol.
Definition: Symbol.cs:20
override string ToString()
Returns a String that represents this Symbol.
Definition: Symbol.cs:83
The SEQUENCE OF type represents a list of data sets..
Definition: SequenceOf.cs:8
static readonly Symbol Choice
Definition: Symbol.cs:202
static readonly Symbol String
Definition: Symbol.cs:210