NTP Analyzer  0.8.2
Analyze the operation of time servers
ConfigParser.cs
Go to the documentation of this file.
1 //
2 // Copyright (c) 2013-2017 Carsten Sonne Larsen <cs@innolan.net>
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 
22 using System;
23 using System.Collections.Generic;
24 using System.Text;
28 using Ntp.Analyzer.Config.Table;
29 
30 namespace Ntp.Analyzer.Config.Compiler
31 {
35  public sealed class ConfigParser : ICompilerStage, IDisposable
36  {
42  public ConfigParser(string file, ISyntaxNode root)
43  {
44  this.root = root;
45  tokenizer = new Tokenizer(file);
46  errors = new List<string>();
47  }
48 
49  private readonly List<string> errors;
50  private readonly ISyntaxNode root;
51  private readonly Tokenizer tokenizer;
52 
57  public SymbolTable SymbolTable { get; set; }
58 
63  public IEnumerable<string> Errors => errors;
64 
68  public void Execute()
69  {
70  var node = root;
71  var pass = true;
72 
73  do
74  {
75  tokenizer.Consume();
76  switch (tokenizer.GetNext().Symbol)
77  {
78  case Symbol.KeywordDatabase:
79  ParseDatabaseSection(node);
80  break;
81  case Symbol.KeywordPermission:
82  ParsePermissionSection(node);
83  break;
84  case Symbol.KeywordNotify:
85  ParseNotifySection(node);
86  break;
87  case Symbol.KeywordDaemon:
88  case Symbol.KeywordService:
89  ParseHeartbeatSection(node);
90  break;
91  case Symbol.KeywordReading:
92  ParseReadingSection(node);
93  break;
94  case Symbol.KeywordLog:
95  ParseLogSection(node);
96  break;
97  case Symbol.KeywordListener:
98  ParseListenerSection(node);
99  break;
100  case Symbol.KeywordServer:
101  ParseHostSection(node);
102  break;
103  default:
104  pass = false;
105  break;
106  }
107  } while (pass);
108 
109  if (errors.Count == 0 && tokenizer.PeekNext() != Token.EndOfFile)
110  {
111  LogError("Unknown section.");
112  }
113  }
114 
115  public void Dispose()
116  {
117  tokenizer.Dispose();
118  }
119 
120  private void AddToSymbolTable(string name, ISyntaxNode node)
121  {
122  var current = SymbolTable.Lookup(name);
123 
124  if (current != null)
125  {
126  LogError($"section {name} is already defined. Choose another name.");
127  }
128  else
129  {
130  SymbolTable.Add(name, node);
131  }
132  }
133 
134  private void LogError(string error)
135  {
136  string entry = $"Error in line {tokenizer.LineNumber} column {tokenizer.ColumnNumber}: {error}";
137  errors.Add(entry);
138  }
139 
140  private void ParseAboutPageSection(ISyntaxNode parent)
141  {
142  var name = ParseSectionStart();
143  var node = new AboutPageSyntaxNode(name, tokenizer.LineNumber);
144  var pass = true;
145 
146  do
147  {
148  tokenizer.Consume();
149  switch (tokenizer.GetNext().Symbol)
150  {
151  case Symbol.KeywordFrequency:
152  case Symbol.KeywordInitialRun:
153  case Symbol.KeywordFixedRun:
154  case Symbol.KeywordTitle:
155  case Symbol.KeywordPageTitle:
156  case Symbol.KeywordServerId:
157  case Symbol.KeywordContentTitle:
158  case Symbol.KeywordLink:
159  ParseValue(node);
160  break;
161  case Symbol.KeywordPageTemplate:
162  ParseOption<PageThemeNode>(node, new List<Symbol>
163  {
164  Symbol.KeywordDefault,
165  Symbol.KeywordBootstrap
166  });
167  break;
168  case Symbol.KeywordContent:
169  ParseContentSection(node);
170  break;
171  case Symbol.KeywordDestinations:
172  ParseFileDestinationSection(node);
173  break;
174  default:
175  pass = false;
176  break;
177  }
178  } while (pass);
179 
180  ParseSectionEnd(name);
181  parent.Add(node);
182  AddToSymbolTable(name, node);
183  }
184 
185  private void ParseContentSection(ISyntaxNode parent)
186  {
187  tokenizer.Consume();
188 
189  if (tokenizer.GetNext().Symbol != Symbol.OpeningBrace)
190  LogError("Content section should begin with an opening brace.");
191 
192  tokenizer.Consume();
193 
194  Token token;
195  var content = new StringBuilder();
196  while ((token = tokenizer.GetNext()).Symbol != Symbol.ClosingBrace)
197  content.Append(token.Text);
198 
199  var node = new StringSettingNode(Keyword.Content, content.ToString(), tokenizer.LineNumber);
200  parent.Add(node);
201  }
202 
203  private void ParseDatabaseSection(ISyntaxNode parent)
204  {
205  var name = ParseSectionStart();
206  var node = new DatabaseSyntaxNode(name, tokenizer.LineNumber);
207  var pass = true;
208 
209  do
210  {
211  tokenizer.Consume();
212  switch (tokenizer.GetNext().Symbol)
213  {
214  case Symbol.KeywordName:
215  case Symbol.KeywordHost:
216  case Symbol.KeywordIp:
217  case Symbol.KeywordAddress:
218  case Symbol.KeywordHostAddress:
219  case Symbol.KeywordPort:
220  case Symbol.KeywordUser:
221  case Symbol.KeywordPass:
222  case Symbol.KeywordCreate:
223  case Symbol.KeywordUpgrade:
224  case Symbol.KeywordImport:
225  case Symbol.KeywordDatabaseName:
226  case Symbol.KeywordDatabaseUser:
227  case Symbol.KeywordDatabasePass:
228  case Symbol.KeywordConString:
229  case Symbol.KeywordCertFile:
230  case Symbol.KeywordCertPass:
231  case Symbol.KeywordConnectionTimeout:
232  case Symbol.KeywordProtocol:
233  case Symbol.KeywordEnableSsl:
234  ParseValue(node);
235  break;
236  case Symbol.KeywordDatabaseProvider:
237  ParseOption<DatabaseProviderNode>(node, new List<Symbol>
238  {
239  Symbol.KeywordDatabaseProviderMySql,
240  Symbol.KeywordDatabaseProviderPostgre
241  });
242  break;
243  case Symbol.KeywordSslMode:
244  ParseOption<DatabaseProviderNode>(node, new List<Symbol>
245  {
246  Symbol.KeywordRequired,
247  Symbol.KeywordPreferred
248  });
249  break;
250  default:
251  pass = false;
252  break;
253  }
254  } while (pass);
255 
256  ParseSectionEnd(name);
257  parent.Add(node);
258  }
259 
260  private void ParseDelimiter()
261  {
262  if (tokenizer.PeekNext() == Token.NewLine)
263  return;
264 
265  tokenizer.ConsumeWhiteSpaces();
266  if (tokenizer.PeekNext() != Token.NewLine)
267  LogError("Expected end of line.");
268  }
269 
271  {
272  var name = ParseSectionStart();
273  var node = new DirDestinationSyntaxNode(name, tokenizer.LineNumber);
274  var pass = true;
275 
276  do
277  {
278  tokenizer.Consume();
279  switch (tokenizer.GetNext().Symbol)
280  {
281  case Symbol.KeywordPrefix:
282  case Symbol.KeywordDirectory:
283  ParseValue(node);
284  break;
285  default:
286  pass = false;
287  break;
288  }
289  } while (pass);
290 
291  ParseSectionEnd(name);
292  parent.Add(node);
293  }
294 
296  {
297  var name = ParseSectionStart();
298  var node = new FileDestinationSyntaxNode(name, tokenizer.LineNumber);
299  var pass = true;
300 
301  do
302  {
303  tokenizer.Consume();
304  if (tokenizer.GetNext().Symbol == Symbol.KeywordFile)
305  ParseValue(node);
306  else
307  pass = false;
308  } while (pass);
309 
310  ParseSectionEnd(name);
311  parent.Add(node);
312  }
313 
314  private void ParseGraphSetSection(ISyntaxNode parent)
315  {
316  var name = ParseSectionStart();
317  var node = new GraphSetSyntaxNode(name, parent.Symbol, tokenizer.LineNumber);
318  var pass = true;
319 
320  do
321  {
322  tokenizer.Consume();
323  switch (tokenizer.GetNext().Symbol)
324  {
325  case Symbol.KeywordTitle:
326  case Symbol.KeywordLinkIndex:
327  case Symbol.KeywordGraph:
328  ParseValue(node);
329  break;
330  default:
331  pass = false;
332  break;
333  }
334  } while (pass);
335 
336  ParseSectionEnd(name);
337  parent.Add(node);
338  }
339 
340  private void ParseHeartbeatSection(ISyntaxNode parent)
341  {
342  var name = ParseSectionStart();
343  var node = new HeartbeatSyntaxNode(name, tokenizer.LineNumber);
344  var pass = true;
345 
346  do
347  {
348  tokenizer.Consume();
349  if (tokenizer.GetNext().Symbol == Symbol.KeywordHeartbeat)
350  ParseValue(node);
351  else
352  pass = false;
353  } while (pass);
354 
355  ParseSectionEnd(name);
356  parent.Add(node);
357  }
358 
360  {
361  var name = ParseSectionStart();
362  var node = new HostGraphPageSyntaxNode(name, tokenizer.LineNumber);
363  var pass = true;
364 
365  do
366  {
367  tokenizer.Consume();
368  switch (tokenizer.GetNext().Symbol)
369  {
370  case Symbol.KeywordFrequency:
371  case Symbol.KeywordInitialRun:
372  case Symbol.KeywordFixedRun:
373  case Symbol.KeywordGraphPage:
374  case Symbol.KeywordLinkIndex:
375  case Symbol.KeywordLink:
376  ParseValue(node);
377  break;
378  case Symbol.KeywordDestinations:
379  ParseDirectoryDestinationSection(node);
380  break;
381  default:
382  pass = false;
383  break;
384  }
385  } while (pass);
386 
387  ParseSectionEnd(name);
388  parent.Add(node);
389  AddToSymbolTable(name, node);
390  }
391 
396  private void ParseHostGraphSection(ISyntaxNode parent)
397  {
398  var name = ParseSectionStart();
399  var node = new HostGraphSyntaxNode(name, tokenizer.LineNumber);
400  var pass = true;
401 
402  do
403  {
404  tokenizer.Consume();
405  switch (tokenizer.GetNext().Symbol)
406  {
407  case Symbol.KeywordFrequency:
408  case Symbol.KeywordInitialRun:
409  case Symbol.KeywordFixedRun:
410  case Symbol.KeywordTitle:
411  case Symbol.KeywordWidth:
412  case Symbol.KeywordHeight:
413  case Symbol.KeywordTimespan:
414  case Symbol.KeywordFilterFactor:
415  case Symbol.KeywordJitter:
416  case Symbol.KeywordOffset:
417  case Symbol.KeywordGraphFrequency:
418  case Symbol.KeywordGraphStability:
419  ParseValue(node);
420  break;
421  case Symbol.KeywordDestinations:
422  ParseFileDestinationSection(node);
423  break;
424  case Symbol.KeywordWebLinks:
425  ParseWebLinkSection(node);
426  break;
427  case Symbol.KeywordGraphTime:
428  case Symbol.KeywordTimeStamp:
429  ParseOption<TimeStampNode>(node, new List<Symbol>
430  {
431  Symbol.KeywordTimeStampLocal,
432  Symbol.KeywordTimeStampUtc
433  });
434  break;
435  default:
436  pass = false;
437  break;
438  }
439  } while (pass);
440 
441  ParseSectionEnd(name);
442  parent.Add(node);
443  AddToSymbolTable(name, node);
444  }
445 
450  private void ParseHostPageSection(ISyntaxNode parent)
451  {
452  var name = ParseSectionStart();
453  var node = new HostPageSyntaxNode(name, tokenizer.LineNumber);
454  var pass = true;
455 
456  do
457  {
458  tokenizer.Consume();
459  switch (tokenizer.GetNext().Symbol)
460  {
461  case Symbol.KeywordFrequency:
462  case Symbol.KeywordInitialRun:
463  case Symbol.KeywordFixedRun:
464  case Symbol.KeywordPageTitle:
465  case Symbol.KeywordLink:
466  case Symbol.KeywordPoolMember:
467  case Symbol.KeywordQueryDirect:
468  case Symbol.KeywordPeerPage:
469  ParseValue(node);
470  break;
471  case Symbol.KeywordPageTemplate:
472  ParseOption<PageThemeNode>(node, new List<Symbol>
473  {
474  Symbol.KeywordDefault,
475  Symbol.KeywordBootstrap
476  });
477  break;
478  case Symbol.KeywordPageTime:
479  case Symbol.KeywordTimeStamp:
480  ParseOption<TimeStampNode>(node, new List<Symbol>
481  {
482  Symbol.KeywordTimeStampLocal,
483  Symbol.KeywordTimeStampUtc
484  });
485  break;
486  case Symbol.KeywordGraphSet:
487  ParseGraphSetSection(node);
488  break;
489  case Symbol.KeywordSummaries:
490  ParseSummariesSection(node);
491  break;
492  case Symbol.KeywordDestinations:
493  ParseFileDestinationSection(node);
494  break;
495  default:
496  pass = false;
497  break;
498  }
499  } while (pass);
500 
501  ParseSectionEnd(name);
502  parent.Add(node);
503  AddToSymbolTable(name, node);
504  }
505 
506  private void ParseHostSection(ISyntaxNode parent)
507  {
508  var name = ParseSectionStart();
509  var node = new HostSyntaxNode(name, tokenizer.LineNumber);
510  var pass = true;
511 
512  do
513  {
514  tokenizer.Consume();
515  switch (tokenizer.GetNext().Symbol)
516  {
517  case Symbol.KeywordHostId:
518  case Symbol.KeywordIp:
519  case Symbol.KeywordAddress:
520  case Symbol.KeywordHostAddress:
521  case Symbol.KeywordFilePath:
522  case Symbol.KeywordWebPath:
523  ParseValue(node);
524  break;
525  case Symbol.KeywordHostType:
526  ParseOption<HostTypeNode>(node, new List<Symbol>
527  {
528  Symbol.KeywordNtpdc,
529  Symbol.KeywordNtpq,
530  Symbol.KeywordNtpctl
531  });
532  break;
533  case Symbol.KeywordTimeStamp:
534  ParseOption<TimeStampNode>(node, new List<Symbol>
535  {
536  Symbol.KeywordTimeStampLocal,
537  Symbol.KeywordTimeStampUtc
538  });
539  break;
540  case Symbol.KeywordAboutPage:
541  ParseAboutPageSection(node);
542  break;
543  case Symbol.KeywordHostPage:
544  ParseHostPageSection(node);
545  break;
546  case Symbol.KeywordPeerPage:
547  ParsePeerPageSection(node);
548  break;
549  case Symbol.KeywordHostGraph:
550  ParseHostGraphSection(node);
551  break;
552  case Symbol.KeywordPeerGraph:
553  ParsePeerGraphSection(node);
554  break;
555  case Symbol.KeywordTrafficGraph:
556  ParseTrafficGraphSection(node);
557  break;
558  case Symbol.KeywordPeerSummaryPage:
559  ParsePeerSummaryPageSection(node);
560  break;
561  case Symbol.KeywordHostGraphPage:
562  ParseHostGraphPageSection(node);
563  break;
564  case Symbol.KeywordPeerGraphPage:
565  ParsePeerGraphPageSection(node);
566  break;
567  case Symbol.KeywordMenu:
568  ParseMenuSection(node);
569  break;
570  case Symbol.KeywordHostStats:
571  case Symbol.KeywordHostIoStats:
572  case Symbol.KeywordPeerStats:
573  case Symbol.KeywordDriftStats:
574  ParseStatSection(node);
575  break;
576  default:
577  pass = false;
578  break;
579  }
580  } while (pass);
581 
582  ParseSectionEnd(name);
583  parent.Add(node);
584  }
585 
586  private void ParseIntOrString(ISyntaxNode parent)
587  {
588  var keyword = ((KeywordToken) tokenizer.Token).Keyword;
589  tokenizer.ConsumeWhiteSpaces();
590  var token = tokenizer.GetNext();
591 
592  switch (token.TokenType)
593  {
594  case TokenType.IntegerValue:
595  parent.Add(new IntegerSettingNode(keyword, ((IntegerToken) token).Value, tokenizer.LineNumber));
596  break;
597  case TokenType.Literal:
598  case TokenType.QuotedIdent:
599  parent.Add(new StringSettingNode(keyword, token.Text, tokenizer.LineNumber));
600  break;
601  default:
602  LogError($"{keyword.Name} must be either an integer or a string.");
603  break;
604  }
605  }
606 
607  private void ParseListenerSection(ISyntaxNode parent)
608  {
609  var name = ParseSectionStart();
610  var node = new ListenerSyntaxNode(name, tokenizer.LineNumber);
611  var pass = true;
612 
613  do
614  {
615  tokenizer.Consume();
616  var token = tokenizer.GetNext();
617 
618  switch (token.Symbol)
619  {
620  case Symbol.KeywordIp:
621  ParseValue(node);
622  break;
623  case Symbol.KeywordPort:
624  ParseValue(node);
625  break;
626  default:
627  pass = false;
628  break;
629  }
630  } while (pass);
631 
632  ParseSectionEnd(name);
633  parent.Add(node);
634  }
635 
636  private void ParseLogSection(ISyntaxNode parent)
637  {
638  var name = ParseSectionStart();
639  var node = new LogSyntaxNode(name, tokenizer.LineNumber);
640  var pass = true;
641 
642  do
643  {
644  tokenizer.Consume();
645  switch (tokenizer.GetNext().Symbol)
646  {
647  case Symbol.KeywordType:
648  ParseOption<LogTypeNode>(node, new List<Symbol>
649  {
650  Symbol.KeywordFile,
651  Symbol.KeywordSyslog,
652  Symbol.KeywordConsole
653  });
654  break;
655  case Symbol.KeywordSeverity:
656  ParseOption<SeverityNode>(node, new List<Symbol>
657  {
658  Symbol.KeywordError,
659  Symbol.KeywordWarn,
660  Symbol.KeywordNotice,
661  Symbol.KeywordInfo,
662  Symbol.KeywordDebug,
663  Symbol.KeywordTrace
664  });
665  break;
666  case Symbol.KeywordShowTimestamp:
667  case Symbol.KeywordShowSeverity:
668  case Symbol.KeywordTimeFormat:
669  case Symbol.KeywordFile:
670  ParseValue(node);
671  break;
672  default:
673  pass = false;
674  break;
675  }
676  } while (pass);
677 
678  ParseSectionEnd(name);
679  parent.Add(node);
680  }
681 
682  private void ParseMenuItem(ISyntaxNode parent)
683  {
684  var name = ParseSectionStart();
685  var node = new MenuItemSyntaxNode(name, tokenizer.LineNumber);
686  var pass = true;
687 
688  do
689  {
690  tokenizer.Consume();
691  switch (tokenizer.GetNext().Symbol)
692  {
693  case Symbol.KeywordPage:
694  case Symbol.KeywordCaption:
695  case Symbol.KeywordLink:
696  case Symbol.KeywordDropdown:
697  ParseValue(node);
698  break;
699  case Symbol.KeywordType:
700  ParseMenuItemType(node);
701  break;
702  case Symbol.KeywordContent:
703  ParseMenuSection(node);
704  break;
705  default:
706  pass = false;
707  break;
708  }
709  } while (pass);
710 
711  ParseSectionEnd(name);
712  parent.Add(node);
713  }
714 
715  private void ParseMenuItemType(ISyntaxNode node)
716  {
717  tokenizer.Consume();
718  var token = tokenizer.GetNext();
719 
720  switch (token.Symbol)
721  {
722  case Symbol.KeywordLink:
723  case Symbol.KeywordName:
724  case Symbol.KeywordPage:
725  case Symbol.KeywordSpacer:
726  case Symbol.KeywordHeader:
727  node.Add(new MenuItemTypeNode {Value = token.Symbol});
728  break;
729  case Symbol.KeywordDropdown:
730  ParseMenuItem(node);
731  break;
732  default:
733  node.Add(new MenuItemTypeNode {Value = Symbol.Unknown});
734  break;
735  }
736  }
737 
738  private void ParseMenuSection(ISyntaxNode parent)
739  {
740  var name = ParseSectionStart();
741  var node = new MenuSyntaxNode(name, tokenizer.LineNumber);
742  var pass = true;
743 
744  do
745  {
746  tokenizer.Consume();
747  if (tokenizer.GetNext().Symbol == Symbol.KeywordItem)
748  ParseMenuItem(node);
749  else
750  pass = false;
751  } while (pass);
752 
753  ParseSectionEnd(name);
754  parent.Add(node);
755  }
756 
757  private void ParseNotifySection(ISyntaxNode parent)
758  {
759  var name = ParseSectionStart();
760  var node = new NotifySyntaxNode(name, tokenizer.LineNumber);
761  var pass = true;
762 
763  do
764  {
765  tokenizer.Consume();
766  switch (tokenizer.GetNext().Symbol)
767  {
768  case Symbol.KeywordFrequency:
769  case Symbol.KeywordInitialRun:
770  case Symbol.KeywordFixedRun:
771  case Symbol.KeywordUser:
772  case Symbol.KeywordPass:
773  case Symbol.KeywordIp:
774  case Symbol.KeywordHost:
775  case Symbol.KeywordAddress:
776  case Symbol.KeywordHostAddress:
777  case Symbol.KeywordPort:
778  case Symbol.KeywordEnableSsl:
779  case Symbol.KeywordSender:
780  case Symbol.KeywordMail:
781  case Symbol.KeywordRecipient:
782  case Symbol.KeywordSubject:
783  case Symbol.KeywordSmtpHost:
784  case Symbol.KeywordSmtpPort:
785  case Symbol.KeywordSmtpUser:
786  case Symbol.KeywordSmtpPass:
787  ParseValue(node);
788  break;
789  default:
790  pass = false;
791  break;
792  }
793  } while (pass);
794 
795  ParseSectionEnd(name);
796  parent.Add(node);
797  }
798 
804  private void ParseOption<T>(ISyntaxNode node, List<Symbol> options)
805  where T : SymbolSettingNode, new()
806  {
807  tokenizer.ConsumeWhiteSpaces();
808  var token = tokenizer.GetNext();
809 
810  if (options.Contains(token.Symbol))
811  node.Add(new T {Value = token.Symbol});
812  else
813  {
814  var keyword = ((KeywordToken) tokenizer.Token).Keyword;
815  LogError($"Invalid value for option {keyword}");
816  }
817 
818  ParseDelimiter();
819  }
820 
822  {
823  var name = ParseSectionStart();
824  var node = new PeerGraphPageSyntaxNode(name, tokenizer.LineNumber);
825  var pass = true;
826 
827  do
828  {
829  tokenizer.Consume();
830  switch (tokenizer.GetNext().Symbol)
831  {
832  case Symbol.KeywordFrequency:
833  case Symbol.KeywordInitialRun:
834  case Symbol.KeywordFixedRun:
835  case Symbol.KeywordGraphPage:
836  case Symbol.KeywordLinkIndex:
837  case Symbol.KeywordLink:
838  ParseValue(node);
839  break;
840  case Symbol.KeywordDestinations:
841  ParseDirectoryDestinationSection(node);
842  break;
843  default:
844  pass = false;
845  break;
846  }
847  } while (pass);
848 
849  ParseSectionEnd(name);
850  parent.Add(node);
851  AddToSymbolTable(name, node);
852  }
853 
858  private void ParsePeerGraphSection(ISyntaxNode parent)
859  {
860  var name = ParseSectionStart();
861  var node = new PeerGraphSyntaxNode(name, tokenizer.LineNumber);
862  var pass = true;
863 
864  do
865  {
866  tokenizer.Consume();
867  switch (tokenizer.GetNext().Symbol)
868  {
869  case Symbol.KeywordFrequency:
870  case Symbol.KeywordInitialRun:
871  case Symbol.KeywordFixedRun:
872  case Symbol.KeywordTitle:
873  case Symbol.KeywordWidth:
874  case Symbol.KeywordHeight:
875  case Symbol.KeywordTimespan:
876  case Symbol.KeywordFilterFactor:
877  case Symbol.KeywordJitter:
878  case Symbol.KeywordOffset:
879  case Symbol.KeywordGraphBalance:
880  case Symbol.KeywordGraphDelay:
881  ParseValue(node);
882  break;
883  case Symbol.KeywordDestinations:
884  ParseDirectoryDestinationSection(node);
885  break;
886  case Symbol.KeywordWebLinks:
887  ParseWebLinkSection(node);
888  break;
889  case Symbol.KeywordGraphTime:
890  case Symbol.KeywordTimeStamp:
891  ParseOption<TimeStampNode>(node, new List<Symbol>
892  {
893  Symbol.KeywordTimeStampLocal,
894  Symbol.KeywordTimeStampUtc
895  });
896  break;
897  default:
898  pass = false;
899  break;
900  }
901  } while (pass);
902 
903  ParseSectionEnd(name);
904  parent.Add(node);
905  AddToSymbolTable(name, node);
906  }
907 
908  private void ParsePeerPageSection(ISyntaxNode parent)
909  {
910  var name = ParseSectionStart();
911  var node = new PeerPageSyntaxNode(name, tokenizer.LineNumber);
912  var pass = true;
913 
914  do
915  {
916  tokenizer.Consume();
917  switch (tokenizer.GetNext().Symbol)
918  {
919  case Symbol.KeywordFrequency:
920  case Symbol.KeywordInitialRun:
921  case Symbol.KeywordFixedRun:
922  case Symbol.KeywordTitle:
923  case Symbol.KeywordPageTitle:
924  case Symbol.KeywordLink:
925  ParseValue(node);
926  break;
927  case Symbol.KeywordPageTemplate:
928  ParseOption<PageThemeNode>(node, new List<Symbol>
929  {
930  Symbol.KeywordDefault,
931  Symbol.KeywordBootstrap
932  });
933  break;
934  case Symbol.KeywordTimeStamp:
935  case Symbol.KeywordPageTime:
936  ParseOption<TimeStampNode>(node, new List<Symbol>
937  {
938  Symbol.KeywordTimeStampLocal,
939  Symbol.KeywordTimeStampUtc
940  });
941  break;
942  case Symbol.KeywordGraphSet:
943  ParseGraphSetSection(node);
944  break;
945  case Symbol.KeywordDestinations:
946  ParseDirectoryDestinationSection(node);
947  break;
948  default:
949  pass = false;
950  break;
951  }
952  } while (pass);
953 
954  ParseSectionEnd(name);
955  parent.Add(node);
956  AddToSymbolTable(name, node);
957  }
958 
960  {
961  var name = ParseSectionStart();
962  var node = new PeerSummaryPageSyntaxNode(name, tokenizer.LineNumber);
963  var pass = true;
964 
965  do
966  {
967  tokenizer.Consume();
968  switch (tokenizer.GetNext().Symbol)
969  {
970  case Symbol.KeywordFrequency:
971  case Symbol.KeywordInitialRun:
972  case Symbol.KeywordFixedRun:
973  case Symbol.KeywordTitle:
974  case Symbol.KeywordPageTitle:
975  case Symbol.KeywordPeerPage:
976  case Symbol.KeywordLink:
977  ParseValue(node);
978  break;
979  case Symbol.KeywordPageTemplate:
980  ParseOption<PageThemeNode>(node, new List<Symbol>
981  {
982  Symbol.KeywordDefault,
983  Symbol.KeywordBootstrap
984  });
985  break;
986  case Symbol.KeywordGraphSet:
987  ParseGraphSetSection(node);
988  break;
989  case Symbol.KeywordDestinations:
990  ParseFileDestinationSection(node);
991  break;
992  default:
993  pass = false;
994  break;
995  }
996  } while (pass);
997 
998  ParseSectionEnd(name);
999  parent.Add(node);
1000  AddToSymbolTable(name, node);
1001  }
1002 
1004  {
1005  var name = ParseSectionStart();
1006  var node = new PermissionSyntaxNode(name, tokenizer.LineNumber);
1007  var pass = true;
1008 
1009  do
1010  {
1011  tokenizer.Consume();
1012  switch (tokenizer.GetNext().Symbol)
1013  {
1014  case Symbol.KeywordUser:
1015  case Symbol.KeywordExecUser:
1016  case Symbol.KeywordGroup:
1017  ParseIntOrString(node);
1018  break;
1019  case Symbol.KeywordMode:
1020  ParseValue(node);
1021  break;
1022  default:
1023  pass = false;
1024  break;
1025  }
1026  } while (pass);
1027 
1028  ParseSectionEnd(name);
1029  parent.Add(node);
1030  }
1031 
1032  private void ParseReadingSection(ISyntaxNode parent)
1033  {
1034  var name = ParseSectionStart();
1035  var node = new ReadingSyntaxNode(name, tokenizer.LineNumber);
1036  var pass = true;
1037 
1038  do
1039  {
1040  tokenizer.Consume();
1041  switch (tokenizer.GetNext().Symbol)
1042  {
1043  case Symbol.KeywordName:
1044  StringSettingNode nameNode = ParseValue(node) as StringSettingNode;
1045  if (nameNode != null)
1046  name = nameNode.Value;
1047  break;
1048  case Symbol.KeywordFrequency:
1049  case Symbol.KeywordInitialRun:
1050  case Symbol.KeywordFixedRun:
1051  ParseValue(node);
1052  break;
1053  case Symbol.KeywordTimeStamp:
1054  ParseOption<TimeStampNode>(node, new List<Symbol>
1055  {
1056  Symbol.KeywordTimeStampLocal,
1057  Symbol.KeywordTimeStampUtc
1058  });
1059  break;
1060  default:
1061  pass = false;
1062  break;
1063  }
1064  } while (pass);
1065 
1066  ParseSectionEnd(name);
1067  parent.Add(node);
1068  AddToSymbolTable(name, node);
1069  }
1070 
1075  private void ParseSectionEnd(string name)
1076  {
1077  if (tokenizer.Token.Symbol == Symbol.ClosingBrace)
1078  return;
1079 
1080  tokenizer.ConsumeWhiteSpaces();
1081  if (tokenizer.GetNext().Symbol == Symbol.ClosingBrace)
1082  return;
1083 
1084  string errorName = string.IsNullOrWhiteSpace(name)
1085  ? string.Empty
1086  : name + " ";
1087 
1088  LogError($"Configuration section {errorName}has unexpected content.");
1089  }
1090 
1095  private string ParseSectionStart()
1096  {
1097  tokenizer.Consume();
1098  var token = tokenizer.GetNext();
1099 
1100  string name = null;
1101  if (token.IsText)
1102  {
1103  name = token.Text;
1104  tokenizer.Consume();
1105  token = tokenizer.GetNext();
1106  }
1107 
1108  if (token.Symbol != Symbol.OpeningBrace)
1109  LogError("Configuration section should begin with an opening brace.");
1110 
1111  return name;
1112  }
1113 
1118  private void ParseStatSection(ISyntaxNode parent)
1119  {
1120  var symbol = tokenizer.Token.Symbol;
1121  var name = ParseSectionStart();
1122  var node = new StatSyntaxNode(symbol, name, tokenizer.LineNumber);
1123  var pass = true;
1124 
1125  do
1126  {
1127  tokenizer.Consume();
1128  switch (tokenizer.GetNext().Symbol)
1129  {
1130  case Symbol.KeywordInitialRun:
1131  case Symbol.KeywordFixedRun:
1132  case Symbol.KeywordFile:
1133  ParseValue(node);
1134  break;
1135  case Symbol.KeywordFrequency:
1136  ParseIntOrString(node);
1137  break;
1138  case Symbol.KeywordTimeStamp:
1139  ParseOption<TimeStampNode>(node, new List<Symbol>
1140  {
1141  Symbol.KeywordTimeStampLocal,
1142  Symbol.KeywordTimeStampUtc
1143  });
1144  break;
1145  default:
1146  pass = false;
1147  break;
1148  }
1149  } while (pass);
1150 
1151  ParseSectionEnd(name);
1152  parent.Add(node);
1153  }
1154 
1155  private void ParseSummariesSection(ISyntaxNode parent)
1156  {
1157  var name = ParseSectionStart();
1158  var node = new SummariesSyntaxNode(name, tokenizer.LineNumber);
1159  var pass = true;
1160 
1161  do
1162  {
1163  tokenizer.Consume();
1164  if (tokenizer.GetNext().Symbol == Symbol.KeywordPeerSummaryPage)
1165  ParseValue(node);
1166  else
1167  pass = false;
1168  } while (pass);
1169 
1170  ParseSectionEnd(name);
1171  parent.Add(node);
1172  }
1173 
1179  {
1180  var name = ParseSectionStart();
1181  var node = new TrafficGraphSyntaxNode(name, tokenizer.LineNumber);
1182  var pass = true;
1183 
1184  do
1185  {
1186  tokenizer.Consume();
1187  switch (tokenizer.GetNext().Symbol)
1188  {
1189  case Symbol.KeywordFrequency:
1190  case Symbol.KeywordInitialRun:
1191  case Symbol.KeywordFixedRun:
1192  case Symbol.KeywordTitle:
1193  case Symbol.KeywordWidth:
1194  case Symbol.KeywordHeight:
1195  case Symbol.KeywordTimespan:
1196  case Symbol.KeywordGraphReceived:
1197  case Symbol.KeywordGraphIgnored:
1198  case Symbol.KeywordGraphDropped:
1199  case Symbol.KeywordGraphSent:
1200  case Symbol.KeywordGraphNotSent:
1201  case Symbol.KeywordGraphAvgReceived:
1202  case Symbol.KeywordGraphAvgIgnored:
1203  case Symbol.KeywordGraphAvgDropped:
1204  case Symbol.KeywordGraphAvgSent:
1205  case Symbol.KeywordGraphAvgNotSent:
1206  case Symbol.KeywordGraphPlotInterval:
1207  case Symbol.KeywordGraphPacketRate:
1208  ParseValue(node);
1209  break;
1210  case Symbol.KeywordDestinations:
1211  ParseFileDestinationSection(node);
1212  break;
1213  case Symbol.KeywordWebLinks:
1214  ParseWebLinkSection(node);
1215  break;
1216  case Symbol.KeywordGraphTime:
1217  case Symbol.KeywordTimeStamp:
1218  ParseOption<TimeStampNode>(node, new List<Symbol>
1219  {
1220  Symbol.KeywordTimeStampLocal,
1221  Symbol.KeywordTimeStampUtc
1222  });
1223  break;
1224  default:
1225  pass = false;
1226  break;
1227  }
1228  } while (pass);
1229 
1230  ParseSectionEnd(name);
1231  parent.Add(node);
1232  AddToSymbolTable(name, node);
1233  }
1234 
1240  {
1241  var keyword = ((KeywordToken) tokenizer.Token).Keyword;
1242  tokenizer.ConsumeWhiteSpaces();
1243  var token = tokenizer.GetNext();
1244  ISyntaxNode node;
1245 
1246  if (keyword.ValueType == typeof(string) && token.IsText)
1247  node = new StringSettingNode(keyword, token.Text, tokenizer.LineNumber);
1248  else if (keyword.ValueType == typeof(string) && token == Token.NewLine)
1249  node = new StringSettingNode(keyword, string.Empty, tokenizer.LineNumber);
1250  else if (keyword.ValueType == typeof(int) && token.TokenType == TokenType.IntegerValue)
1251  node = new IntegerSettingNode(keyword, ((IntegerToken) token).Value, tokenizer.LineNumber);
1252  else if (keyword.ValueType == typeof(int) && token.Symbol == Symbol.Zero)
1253  node = new IntegerSettingNode(keyword, 0, tokenizer.LineNumber);
1254  else if (keyword.ValueType == typeof(int) && token.Symbol == Symbol.One)
1255  node = new IntegerSettingNode(keyword, 1, tokenizer.LineNumber);
1256  else if (keyword.ValueType == typeof(double) && token.TokenType == TokenType.NumericValue)
1257  node = new NumericSettingNode(keyword, ((NumericToken) token).Value, tokenizer.LineNumber);
1258  else if (keyword.ValueType == typeof(double) && token.TokenType == TokenType.IntegerValue)
1259  node = new NumericSettingNode(keyword, ((IntegerToken) token).Value, tokenizer.LineNumber);
1260  else if (keyword.ValueType == typeof(double) && token.Symbol == Symbol.Zero)
1261  node = new NumericSettingNode(keyword, 0.0, tokenizer.LineNumber);
1262  else if (keyword.ValueType == typeof(double) && token.Symbol == Symbol.One)
1263  node = new NumericSettingNode(keyword, 1.0, tokenizer.LineNumber);
1264  else if (keyword.ValueType == typeof(bool) &&
1265  (token.Symbol == Symbol.BooleanTrue || token.Symbol == Symbol.One))
1266  node = new BooleanSettingNode(keyword, true, tokenizer.LineNumber);
1267  else if (keyword.ValueType == typeof(bool) &&
1268  (token.Symbol == Symbol.BooleanFalse || token.Symbol == Symbol.Zero))
1269  node = new BooleanSettingNode(keyword, false, tokenizer.LineNumber);
1270  else
1271  {
1272  LogError($"Invalid value for setting {keyword.Name}");
1273  ParseDelimiter();
1274  return null;
1275  }
1276 
1277  parent.Add(node);
1278  ParseDelimiter();
1279  return node;
1280  }
1281 
1282  private void ParseWebLinkSection(ISyntaxNode parent)
1283  {
1284  var name = ParseSectionStart();
1285  var node = new WebLinkSyntaxNode(name, tokenizer.LineNumber);
1286  var pass = true;
1287 
1288  do
1289  {
1290  tokenizer.Consume();
1291  if (tokenizer.GetNext().Symbol == Symbol.KeywordLink)
1292  ParseValue(node);
1293  else
1294  pass = false;
1295  } while (pass);
1296 
1297  ParseSectionEnd(name);
1298  parent.Add(node);
1299  }
1300  }
1301 }
void AddToSymbolTable(string name, ISyntaxNode node)
void ParseHostGraphSection(ISyntaxNode parent)
Parses a host graph configuration section.
void ParseHostGraphPageSection(ISyntaxNode parent)
void Execute()
Execute the parser stage.
Definition: ConfigParser.cs:68
void ParsePeerPageSection(ISyntaxNode parent)
void ParseSectionEnd(string name)
Parses the footer of a configuration section.
void ParseLogSection(ISyntaxNode parent)
abstract string Text
Definition: Token.cs:44
void ParseFileDestinationSection(ISyntaxNode parent)
void ParseContentSection(ISyntaxNode parent)
ISyntaxNode ParseValue(ISyntaxNode parent)
Parses the value of a setting.
void ParseMenuItem(ISyntaxNode parent)
void ParseGraphSetSection(ISyntaxNode parent)
void ParseMenuSection(ISyntaxNode parent)
string ParseSectionStart()
Get the header of a configuration section.
void ParseNotifySection(ISyntaxNode parent)
void ParseWebLinkSection(ISyntaxNode parent)
void ParseReadingSection(ISyntaxNode parent)
void Add(ISyntaxNode node)
Definition: SyntaxNode.cs:66
void ParseHostPageSection(ISyntaxNode parent)
Parses a host page configuration section.
void ParseHostSection(ISyntaxNode parent)
void ParseTrafficGraphSection(ISyntaxNode parent)
Parses a traffic graph configuration section.
void ParsePermissionSection(ISyntaxNode parent)
ConfigParser(string file, ISyntaxNode root)
Initializes a new instance of the ConfigParser class.
Definition: ConfigParser.cs:42
void ParsePeerSummaryPageSection(ISyntaxNode parent)
void ParseSummariesSection(ISyntaxNode parent)
void Add(string name, ISyntaxNode node)
Definition: SymbolTable.cs:36
void ParseAboutPageSection(ISyntaxNode parent)
void ParseHeartbeatSection(ISyntaxNode parent)
void ParsePeerGraphPageSection(ISyntaxNode parent)
void ParseListenerSection(ISyntaxNode parent)
void ParseDirectoryDestinationSection(ISyntaxNode parent)
void ParsePeerGraphSection(ISyntaxNode parent)
Parses a peer graph configuration section.
void ParseMenuItemType(ISyntaxNode node)
void ParseStatSection(ISyntaxNode parent)
Parses the stat configuration section.
The config parser transforms configuration texts into a syntax tree.
Definition: ConfigParser.cs:35
ISyntaxNode Lookup(string name)
Definition: SymbolTable.cs:41
void ParseIntOrString(ISyntaxNode parent)
void ParseDatabaseSection(ISyntaxNode parent)