2 using Mercury.Scanning;
3 using Mercury.Interpreting;
6 using System.Collections.Generic;
9 namespace Mercury.Formats.Basic
30 if (epsilon == null || epsilon.Type != SymbolType.Epsilon)
31 throw new ArgumentException(
"Required epsilon symbol for Grammar Entity Parser");
43 FmtChk.AssertNotNull(token,
"token");
45 string sname = token.Value.Unescape();
46 SymbolType stype = sname == Epsilon.Name ? SymbolType.Epsilon : SymbolType.Terminal | SymbolType.Nonterminal;
48 return new Symbol(sname, stype);
61 FmtChk.AssertNotNull(tokens,
"tokens");
62 FmtChk.AssertCount(3, tokens,
"Not a rule");
63 FmtChk.AssertToken(tokens[1],
"->",
"Operator '->' missing");
65 Symbol lhs = ParseSymbol(tokens[0]);
67 return new Rule(lhs, tokens.Skip(2).Select(x => ParseSymbol(x)));
78 FmtChk.AssertNotNull(tokens,
"tokens");
79 FmtChk.AssertCount(3, tokens,
"Not a rule");
81 var prefix = tokens.Take(2).ToArray();
82 var rhs =
new List<Token>();
83 var result =
new List<Rule>();
85 foreach(Token token
in tokens.Skip(2))
86 if (token.Value ==
"|")
88 result.Add(ParseRule(prefix.Concat(rhs).ToList()));
94 result.Add(ParseRule(prefix.Concat(rhs).ToList()));
106 FmtChk.AssertNotNull(tokens,
"tokens");
107 FmtChk.AssertCount(8, tokens,
"Not an edge");
108 FmtChk.AssertPattern(
new[] {
"(", null,
",", null,
")", null,
"->" }, tokens, x => x.Value);
110 int l = int.Parse(tokens[1].Value);
111 int r = int.Parse(tokens[3].Value);
114 List<Token> lhs =
new List<Token> { tokens[5], tokens[6] };
115 List<Token> rhs =
new List<Token>();
117 for (
int tokix = 7; tokix < tokens.Count; ++tokix)
118 if (tokens[tokix].Value ==
".")
120 FmtChk.AssertTrue(d == -1,
"Too many '.' markers in the edge");
124 rhs.Add(tokens[tokix]);
127 rhs.Add(
new Token(Epsilon.Name, TokenType.String, 0));
129 FmtChk.AssertFalse(d == -1,
"Edge mark '.' missing");
131 return new Edge(ParseRule(lhs.Concat(rhs).ToList()), d, l, r);
134 public Symbol Epsilon {
get;
private set; }
149 public class InterpreterEntityParser<T> where T : class
153 internal class AlternativeData
155 public AlternativeData()
157 WildcardSymbols = SymbolType.None;
158 Symbols =
new List<Symbol>();
161 public SymbolType WildcardSymbols {
get; set; }
162 public List<Symbol> Symbols {
get; set; }
166 private IReadOnlyDictionary<string, InterpreterAction<T>> actions;
167 private IReadOnlyDictionary<string, string> aliases;
172 IReadOnlyDictionary<
string, InterpreterAction<T>> actions,
173 IReadOnlyDictionary<string, string> aliases)
176 this.actions = actions;
177 this.aliases = aliases;
187 public IElement
ParseElement(IList<Token> tokens,
int start, out
int end)
189 FmtChk.AssertNotNull(tokens,
"tokens");
190 FmtChk.AssertCount(start + 1, tokens);
192 if (tokens[start].Quoted)
return ParseConstant(tokens, start, out end);
194 switch (tokens[start].Value)
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);
221 FmtChk.AssertNotNull(tokens,
"tokens");
222 FmtChk.AssertCount(start + 1, tokens,
"Not a constant");
224 List<Symbol> smlist =
new List<Symbol>();
225 SymbolType mask = SymbolType.None;
226 while (tokens[start].Value !=
":")
228 var name = tokens[start].Value.Unescape();
229 if (name == gep.Epsilon.Name)
230 mask |= SymbolType.Epsilon;
232 smlist.Add(
new Symbol(name));
234 if ((start + 2 < tokens.Count)
235 && (tokens[start + 2].Value !=
"|")
236 && (tokens[start + 1].Value ==
"|"))
247 if ((start + 1 < tokens.Count) && (tokens[start].Value ==
":"))
249 foreach(
char c
in tokens[start + 1].Value)
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));
262 return new Constant(mask, smlist);
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],
"#");
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));
286 var varname = tokens[start + 1].Value;
290 if ((start + 2 < tokens.Count) && (tokens[start + 2].Value ==
":"))
291 cst = ParseConstant(tokens, start + 3, out end);
293 cst =
new Constant(SymbolType.Any,
new Symbol[0]);
295 return new Variable(varname, cst.SymbolMask, cst.Symbols);
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],
"*");
319 if ((start < tokens.Count) && (tokens[start].Position == tokens[start - 1].Position + 1))
321 name = tokens[start].Value;
327 cst = ((start < tokens.Count) && (tokens[start].Value ==
":"))
328 ? ParseConstant(tokens, start + 1, out end)
329 :
new Constant(SymbolType.Any,
new Symbol[0]);
331 return new Wildcard(name, cst.SymbolMask, cst.Symbols);
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],
"[");
350 List<IElement> elements =
new List<IElement>();
352 while ((ix < tokens.Count) && (tokens[ix].Value !=
"]"))
353 elements.Add(ParseElement(tokens, ix, out ix));
356 FmtChk.AssertTrue(ix < tokens.Count,
"Expected ']' at the end of strucutre");
357 FmtChk.AssertNotEmpty(elements,
"Empty structure is not valid");
359 return new Structure(elements[0], elements.Skip(1));
369 public IFormalParameter
ParseParameter(IList<Token> tokens,
int start, out
int end)
371 FmtChk.AssertNotNull(tokens,
"tokens");
372 FmtChk.AssertCount(start + 1, tokens,
"Not a parameter");
375 if (tokens[start].Quoted)
376 return ConstantParameter.StringParameter(tokens[start].Value.Unescape());
378 switch (tokens[start].Value)
380 case "(":
return ParseActionCall(tokens, start, out end);
383 FmtChk.AssertCount(start + 2, tokens);
386 return new VariableParameter(tokens[start + 1].Value);
390 return ConstantParameter.AutoCreate(tokens[start].Value.Unescape());
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],
"(");
411 string name = name = tokens[start + 1].Value;
413 InterpreterAction<T> action;
414 if (!actions.TryGetValue(name, out action))
417 if (!aliases.TryGetValue(name, out alias) || !actions.TryGetValue(alias, out action))
418 throw new FormatException(
string.Format(
"Action '{0}' not found", name));
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");
426 return new ActionCall<T>(action, fparams);
436 public IFormalParameter[]
ParseParameters(IList<Token> tokens,
int start, out
int end)
438 FmtChk.AssertNotNull(tokens,
"tokens");
439 FmtChk.AssertCount(start + 1, tokens,
"No parameters");
441 List<IFormalParameter> fparams =
new List<IFormalParameter>();
443 int fst = end = start;
444 while ((start < tokens.Count) && (tokens[start].Quoted || (tokens[start].Value !=
")")))
446 fparams.Add(ParseParameter(tokens, start, out end));
450 return fparams.ToArray();
463 FmtChk.AssertNotNull(tokens,
"tokens");
464 FmtChk.AssertNotEmpty(tokens);
467 for (
int ix = 0; (arrow == -1) && (ix < tokens.Count); ++ix)
468 if ((tokens[ix].Type == TokenType.Keyword) && (tokens[ix].Value ==
"==>"))
472 FmtChk.AssertTrue(arrow != -1,
"Missing '==>' in rule");
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");
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));;
481 return new RewriteRule<T>(lhs, rhs);