Mercury.Formats library  1.0
The library provides format parsers for the Mercury library components.
 All Classes Namespaces Files Functions Properties
GrammarParser.cs
Go to the documentation of this file.
1 using Mercury.Scanning;
2 using Mercury.Syntax;
3 using System;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.Linq;
7 
8 namespace Mercury.Formats.Basic
9 {
10 //=============================================================================
11 // StreamGrammarParser
12 //=============================================================================
13 
59  public class GrammarParser : IDisposable
60  {
61  private static Tokenizer inputTokenizer
62  = new Tokenizer(new[] { '@', '_' }, new[] { "->", "root", "epsilon", "metagrammar" }, TokenizerOptions.CompiledMatch);
63 
64  //--[ Private fields ]-----------------------------------------------
65 
66  private StreamReader source = null;
67  private string filename = null;
68 
69  //--[ Constructors ]-------------------------------------------------
70 
79  public GrammarParser(StreamReader reader)
80  {
81  if (reader == null) throw new ArgumentNullException("reader");
82 
83  source = reader;
84  }
85 
90  public GrammarParser(string filename)
91  : this(new StreamReader(filename))
92  {
93  this.filename = filename;
94  }
95 
96  //--[ Methods ]------------------------------------------------------
97 
98  private GrammarBuilder GetBuilder(ref int linenum)
99  {
100  linenum = 0;
101  string line = null;
102 
103  List<Token> tokens = new List<Token>();
104 
105  bool header = true;
106  Symbol root = null;
107  Symbol epsilon = null;
108  while (header && ((line = source.ReadLine()) != null))
109  {
110  ++linenum;
111 
112  tokens.Clear();
113  tokens.AddRange(inputTokenizer.Tokenize(line));
114 
115  if ((tokens.Count == 0) || (tokens[0].Value == "#"))
116  continue;
117 
118  if (tokens[0].Type != TokenType.Keyword)
119  { header = false; break; }
120 
121  switch(tokens[0].Value)
122  {
123  case "root":
124  if (root != null) goto alreadyset;
125  if (tokens.Count != 2) goto syntaxerr;
126 
127  root = new Symbol(tokens[1].Value, SymbolType.Nonterminal);
128  break;
129 
130  case "epsilon":
131  if (epsilon != null) goto alreadyset;
132  if (tokens.Count != 2) goto syntaxerr;
133 
134  epsilon = new Symbol(tokens[1].Value, SymbolType.Epsilon);
135  break;
136 
137  alreadyset: throw new FormatException(string.Format("'{0}' option is already set", tokens[0].Value));
138  syntaxerr: throw new FormatException(string.Format("Invalid syntax of '{0}'", tokens[0].Value));
139 
140  default:
141  header = false;
142  break;
143  }
144  }
145 
146  GrammarBuilder builder= new GrammarBuilder(
147  root ?? new Symbol(Defaults.Root),
148  epsilon ?? new Symbol(Defaults.Epsilon, SymbolType.Epsilon));
149 
150  List<Token> ruletok = new List<Token>();
151  GrammarEntityParser gep = new GrammarEntityParser(builder.Epsilon);
152 
153  Action parse = delegate()
154  {
155  if (ruletok.Count != 0)
156  foreach (var rule in gep.ParseMultiRule(ruletok)) builder.AddRule(rule);
157  ruletok.Clear();
158  };
159 
160  while(line != null)
161  {
162  if ((tokens.Count != 0) && (tokens[0].Value != "#"))
163  {
164  if (tokens[0].Value != "|")
165  parse.Invoke();
166 
167  ruletok.AddRange(tokens);
168  }
169 
170  ++linenum;
171  tokens.Clear();
172  line = source.ReadLine();
173 
174  if (line == null)
175  parse.Invoke();
176  else
177  tokens.AddRange(inputTokenizer.Tokenize(line));
178  }
179 
180  return builder;
181  }
182 
188  public GrammarBuilder GetBuilder()
189  {
190  int linenum = 0;
191 
192  try
193  {
194  return GetBuilder(ref linenum);
195  }
196  catch (Exception ex)
197  {
198  string msg = filename == null
199  ? string.Format("In line {0}: {1}", linenum, ex.Message)
200  : string.Format("In '{0}' line {1}: {2}", filename, linenum, ex.Message);
201 
202  throw new FormatException(msg, ex);
203  }
204  }
205 
206  //--[ Interface implementation ]-------------------------------------
207 
208  #region [ IDisposable ]
209 
210  public void Dispose()
211  { if (filename != null) source.Close(); }
212 
213  #endregion
214 
215  }
216 }
Parses a grammar from a StreamReader. Grammar is expected in the format
GrammarBuilder GetBuilder()
Parses the file provided by the constructor's argument and returns the builder.
GrammarParser(StreamReader reader)
Creates a parser that will parse grammar from provided StreamReader instance.
GrammarParser(string filename)
Initializes a new instance of the GrammarParser class.