Mercury.Formats library  1.0
The library provides format parsers for the Mercury library components.
 All Classes Namespaces Files Functions Properties
EntityParser.cs
Go to the documentation of this file.
1 using Mercury;
2 using Mercury.Scanning;
3 using Mercury.Interpreting;
4 using Mercury.Syntax;
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 
9 namespace Mercury.Formats.Basic
10 {
11 //=============================================================================
12 // GrammarEntityParser
13 //=============================================================================
14 
18  public class GrammarEntityParser
19  {
20 
21  //--[ Constructors ]-------------------------------------------------
22 
28  public GrammarEntityParser(Symbol epsilon)
29  {
30  if (epsilon == null || epsilon.Type != SymbolType.Epsilon)
31  throw new ArgumentException("Required epsilon symbol for Grammar Entity Parser");
32 
33  Epsilon = epsilon;
34  }
35 
36  //--[ Methods ]------------------------------------------------------
37 
41  public Symbol ParseSymbol(Token token)
42  {
43  FmtChk.AssertNotNull(token, "token");
44 
45  string sname = token.Value.Unescape();
46  SymbolType stype = sname == Epsilon.Name ? SymbolType.Epsilon : SymbolType.Terminal | SymbolType.Nonterminal;
47 
48  return new Symbol(sname, stype);
49  }
50 
59  public Rule ParseRule(IList<Token> tokens)
60  {
61  FmtChk.AssertNotNull(tokens, "tokens");
62  FmtChk.AssertCount(3, tokens, "Not a rule");
63  FmtChk.AssertToken(tokens[1], "->", "Operator '->' missing");
64 
65  Symbol lhs = ParseSymbol(tokens[0]);
66 
67  return new Rule(lhs, tokens.Skip(2).Select(x => ParseSymbol(x)));
68  }
69 
76  public IList<Rule> ParseMultiRule(IList<Token> tokens)
77  {
78  FmtChk.AssertNotNull(tokens, "tokens");
79  FmtChk.AssertCount(3, tokens, "Not a rule");
80 
81  var prefix = tokens.Take(2).ToArray();
82  var rhs = new List<Token>();
83  var result = new List<Rule>();
84 
85  foreach(Token token in tokens.Skip(2))
86  if (token.Value == "|")
87  {
88  result.Add(ParseRule(prefix.Concat(rhs).ToList()));
89  rhs.Clear();
90  }
91  else
92  rhs.Add(token);
93 
94  result.Add(ParseRule(prefix.Concat(rhs).ToList()));
95  return result;
96  }
97 
104  public Edge ParseEdge(IList<Token> tokens)
105  {
106  FmtChk.AssertNotNull(tokens, "tokens");
107  FmtChk.AssertCount(8, tokens, "Not an edge");
108  FmtChk.AssertPattern(new[] { "(", null, ",", null, ")", null, "->" }, tokens, x => x.Value);
109 
110  int l = int.Parse(tokens[1].Value);
111  int r = int.Parse(tokens[3].Value);
112  int d = -1;
113 
114  List<Token> lhs = new List<Token> { tokens[5], tokens[6] };
115  List<Token> rhs = new List<Token>();
116 
117  for (int tokix = 7; tokix < tokens.Count; ++tokix)
118  if (tokens[tokix].Value == ".")
119  {
120  FmtChk.AssertTrue(d == -1, "Too many '.' markers in the edge");
121  d = tokix - 7;
122  }
123  else
124  rhs.Add(tokens[tokix]);
125 
126  if (rhs.Count == 0)
127  rhs.Add(new Token(Epsilon.Name, TokenType.String, 0));
128 
129  FmtChk.AssertFalse(d == -1, "Edge mark '.' missing");
130 
131  return new Edge(ParseRule(lhs.Concat(rhs).ToList()), d, l, r);
132  }
133 
134  public Symbol Epsilon { get; private set; }
135  }
136 
137 //=============================================================================
138 // InterpreterEntityParser
139 //=============================================================================
140 
149  public class InterpreterEntityParser<T> where T : class
150  {
151  //--[ Internals ]----------------------------------------------------
152 
153  internal class AlternativeData
154  {
155  public AlternativeData()
156  {
157  WildcardSymbols = SymbolType.None;
158  Symbols = new List<Symbol>();
159  }
160 
161  public SymbolType WildcardSymbols { get; set; }
162  public List<Symbol> Symbols { get; set; }
163  }
164 
165  private GrammarEntityParser gep;
166  private IReadOnlyDictionary<string, InterpreterAction<T>> actions;
167  private IReadOnlyDictionary<string, string> aliases;
168 
169  //--[ Constructors ]-------------------------------------------------
170 
171  public InterpreterEntityParser(Symbol epsilon,
172  IReadOnlyDictionary<string, InterpreterAction<T>> actions,
173  IReadOnlyDictionary<string, string> aliases)
174  {
175  this.gep = new GrammarEntityParser(epsilon);
176  this.actions = actions;
177  this.aliases = aliases;
178  }
179 
180  //--[ Methods ]------------------------------------------------------
181 
187  public IElement ParseElement(IList<Token> tokens, int start, out int end)
188  {
189  FmtChk.AssertNotNull(tokens, "tokens");
190  FmtChk.AssertCount(start + 1, tokens);
191 
192  if (tokens[start].Quoted) return ParseConstant(tokens, start, out end);
193 
194  switch (tokens[start].Value)
195  {
196  case "?": end = start + 1;
197  return new Variable();
198  case "#": return ParseVariable (tokens, start, out end);
199  case "*": return ParseWildcard (tokens, start, out end);
200  case "[": return ParseStructure(tokens, start, out end);
201  default: return ParseConstant (tokens, start, out end);
202  }
203  }
204 
219  public Constant ParseConstant(IList<Token> tokens, int start, out int end)
220  {
221  FmtChk.AssertNotNull(tokens, "tokens");
222  FmtChk.AssertCount(start + 1, tokens, "Not a constant");
223 
224  List<Symbol> smlist = new List<Symbol>();
225  SymbolType mask = SymbolType.None;
226  while (tokens[start].Value != ":")
227  {
228  var name = tokens[start].Value.Unescape();
229  if (name == gep.Epsilon.Name)
230  mask |= SymbolType.Epsilon;
231  else
232  smlist.Add(new Symbol(name));
233 
234  if ((start + 2 < tokens.Count)
235  && (tokens[start + 2].Value != "|")
236  && (tokens[start + 1].Value == "|"))
237  start += 2;
238  else
239  {
240  ++start;
241  break;
242  }
243  }
244 
245  end = start;
246 
247  if ((start + 1 < tokens.Count) && (tokens[start].Value == ":"))
248  {
249  foreach(char c in tokens[start + 1].Value)
250  {
251  switch (c)
252  {
253  case 'N': mask |= SymbolType.Nonterminal; break;
254  case 'T': mask |= SymbolType.Terminal; break;
255  case 'e': mask |= SymbolType.Epsilon; break;
256  default: throw new FormatException(string.Format("Unexpected flag {0} in an alternative", c));
257  }
258  }
259  end = start + 2;
260  }
261 
262  return new Constant(mask, smlist);
263  }
264 
276  public Variable ParseVariable(IList<Token> tokens, int start, out int end)
277  {
278  FmtChk.AssertNotNull(tokens, "tokens");
279  FmtChk.AssertCount(start + 2, tokens, "Not a variable");
280  FmtChk.AssertFalse(tokens[start].Quoted, "Not a variable");
281  FmtChk.AssertToken(tokens[start], "#");
282 
283  if (tokens[start + 1].Position != tokens[start].Position + 1)
284  throw new FormatException(string.Format("Name of variable expected at position {0}", tokens[start].Position + 1));
285 
286  var varname = tokens[start + 1].Value;
287  end = start + 2;
288 
289  Constant cst = null;
290  if ((start + 2 < tokens.Count) && (tokens[start + 2].Value == ":"))
291  cst = ParseConstant(tokens, start + 3, out end);
292  else
293  cst = new Constant(SymbolType.Any, new Symbol[0]);
294 
295  return new Variable(varname, cst.SymbolMask, cst.Symbols);
296  }
297 
309  public Wildcard ParseWildcard(IList<Token> tokens, int start, out int end)
310  {
311  FmtChk.AssertNotNull(tokens, "tokens");
312  FmtChk.AssertCount(start + 1, tokens, "Not a wildcard");
313  FmtChk.AssertFalse(tokens[start].Quoted, "Not a wildcard");
314  FmtChk.AssertToken(tokens[start], "*");
315 
316  end = ++start;
317 
318  string name = null;
319  if ((start < tokens.Count) && (tokens[start].Position == tokens[start - 1].Position + 1))
320  {
321  name = tokens[start].Value;
322  ++start;
323  ++end;
324  }
325 
326  Constant cst = null;
327  cst = ((start < tokens.Count) && (tokens[start].Value == ":"))
328  ? ParseConstant(tokens, start + 1, out end)
329  : new Constant(SymbolType.Any, new Symbol[0]);
330 
331  return new Wildcard(name, cst.SymbolMask, cst.Symbols);
332  }
333 
343  public Structure ParseStructure(IList<Token> tokens, int start, out int end)
344  {
345  FmtChk.AssertNotNull(tokens, "tokens");
346  FmtChk.AssertCount(start + 1, tokens, "Not a structure");
347  FmtChk.AssertFalse(tokens[start].Quoted, "Not a structure");
348  FmtChk.AssertToken(tokens[start], "[");
349 
350  List<IElement> elements = new List<IElement>();
351  int ix = start + 1;
352  while ((ix < tokens.Count) && (tokens[ix].Value != "]"))
353  elements.Add(ParseElement(tokens, ix, out ix));
354 
355  end = ix + 1;
356  FmtChk.AssertTrue(ix < tokens.Count, "Expected ']' at the end of strucutre");
357  FmtChk.AssertNotEmpty(elements, "Empty structure is not valid");
358 
359  return new Structure(elements[0], elements.Skip(1));
360  }
361 
369  public IFormalParameter ParseParameter(IList<Token> tokens, int start, out int end)
370  {
371  FmtChk.AssertNotNull(tokens, "tokens");
372  FmtChk.AssertCount(start + 1, tokens, "Not a parameter");
373 
374  end = start + 1;
375  if (tokens[start].Quoted)
376  return ConstantParameter.StringParameter(tokens[start].Value.Unescape());
377 
378  switch (tokens[start].Value)
379  {
380  case "(": return ParseActionCall(tokens, start, out end);
381 
382  case "#":
383  FmtChk.AssertCount(start + 2, tokens);
384 
385  end = start + 2;
386  return new VariableParameter(tokens[start + 1].Value);
387 
388  default:
389  end = start + 1;
390  return ConstantParameter.AutoCreate(tokens[start].Value.Unescape());
391  }
392  }
393 
404  public ActionCall<T> ParseActionCall(IList<Token> tokens, int start, out int end)
405  {
406  FmtChk.AssertNotNull(tokens, "tokens");
407  FmtChk.AssertCount(start + 3, tokens, "Not an action");
408  FmtChk.AssertFalse(tokens[start].Quoted, "Not an action");
409  FmtChk.AssertToken(tokens[start], "(");
410 
411  string name = name = tokens[start + 1].Value;
412 
413  InterpreterAction<T> action;
414  if (!actions.TryGetValue(name, out action))
415  {
416  string alias = null;
417  if (!aliases.TryGetValue(name, out alias) || !actions.TryGetValue(alias, out action))
418  throw new FormatException(string.Format("Action '{0}' not found", name));
419  }
420 
421  IFormalParameter[] fparams = ParseParameters(tokens, start + 2, out end);
422  if (end >= tokens.Count || tokens[end].Value != ")")
423  throw new ArgumentException("Expected ')' at the end of action call");
424  ++end;
425 
426  return new ActionCall<T>(action, fparams);
427  }
428 
436  public IFormalParameter[] ParseParameters(IList<Token> tokens, int start, out int end)
437  {
438  FmtChk.AssertNotNull(tokens, "tokens");
439  FmtChk.AssertCount(start + 1, tokens, "No parameters");
440 
441  List<IFormalParameter> fparams = new List<IFormalParameter>();
442 
443  int fst = end = start;
444  while ((start < tokens.Count) && (tokens[start].Quoted || (tokens[start].Value != ")")))
445  {
446  fparams.Add(ParseParameter(tokens, start, out end));
447  start = end;
448  };
449 
450  return fparams.ToArray();
451  }
452 
461  public RewriteRule<T> ParseRewriteRule(IList<Token> tokens)
462  {
463  FmtChk.AssertNotNull(tokens, "tokens");
464  FmtChk.AssertNotEmpty(tokens);
465 
466  int arrow = -1;
467  for (int ix = 0; (arrow == -1) && (ix < tokens.Count); ++ix)
468  if ((tokens[ix].Type == TokenType.Keyword) && (tokens[ix].Value == "==>"))
469  arrow = ix;
470 
471  int end;
472  FmtChk.AssertTrue(arrow != -1, "Missing '==>' in rule");
473 
474  Structure lhs = ParseElement(tokens, 0, out end) as Structure;
475  FmtChk.AssertNotNull(lhs, "Missing LHS structure");
476  FmtChk.AssertTrue(end == arrow, "Invalid LHS structure");
477 
478  ActionCall<T> rhs = ParseActionCall(tokens, arrow + 1, out end);
479  if (end != tokens.Count) throw new ArgumentException(string.Format("Unexpected token '{0}' after action", tokens[end].Value));;
480 
481  return new RewriteRule<T>(lhs, rhs);
482  }
483  }
484 }
InterpreterEntityParser(Symbol epsilon, IReadOnlyDictionary< string, InterpreterAction< T >> actions, IReadOnlyDictionary< string, string > aliases)
Symbol ParseSymbol(Token token)
Parses a symbol from a token.
Definition: EntityParser.cs:41
IFormalParameter[] ParseParameters(IList< Token > tokens, int start, out int end)
Parses the parameters of an action call.
GrammarEntityParser(Symbol epsilon)
Initializes a new instance of the GrammarEntityParser class.
Definition: EntityParser.cs:28
IList< Rule > ParseMultiRule(IList< Token > tokens)
Parses the multi-rule. It is of the form A -> RHS0 | RHS1 | ... where A -> RHS0 and A -> RHS1 are val...
Definition: EntityParser.cs:76
IElement ParseElement(IList< Token > tokens, int start, out int end)
Parses the element.
Structure ParseStructure(IList< Token > tokens, int start, out int end)
Parses the structure. It is of the form [Root Elements...] where Root is an Mercury.Interpreting.Alternative and Elements is a list of elements.
Rule ParseRule(IList< Token > tokens)
Parses the rule. The rule is of the format A -> X Y Z... where A is a nonterminal symbols and X...
Definition: EntityParser.cs:59
Wildcard ParseWildcard(IList< Token > tokens, int start, out int end)
Parses the wildcard. It is of the form *name:alternative. The same conditions hold as in ParseVariabl...
Edge ParseEdge(IList< Token > tokens)
Parses the edge. It is of the form (l, r) A -> alpha . beta where l <= r and A -> alpha beta is a val...
Class for parsing grammar entities used in Mercury.
Definition: EntityParser.cs:18
IFormalParameter ParseParameter(IList< Token > tokens, int start, out int end)
Parses the parameter. It might be a constant or an action call.
ActionCall< T > ParseActionCall(IList< Token > tokens, int start, out int end)
Parses the action call. It is of the form (f x y z...) where f is a name of an action and x...
Constant ParseConstant(IList< Token > tokens, int start, out int end)
Parses the constant. It is of the form symbols:mask where symbols is a list of symbols separated by |...
RewriteRule< T > ParseRewriteRule(IList< Token > tokens)
Parses the rewrite rule. It is of the form LHS ==> RHS where LHS is a Mercury.Interpreting.Structure and RHS is an Mercury.Interpreting.ActionCall{T}.
Variable ParseVariable(IList< Token > tokens, int start, out int end)
Parses the variable. It is of the form #name:alternative where name is a variable name and alternativ...