1 using Mercury.Scanning;
4 using System.Collections.Generic;
8 namespace Mercury.Formats.Basic
61 private static Tokenizer inputTokenizer
62 =
new Tokenizer(
new[] {
'@',
'_' },
new[] {
"->",
"root",
"epsilon",
"metagrammar" }, TokenizerOptions.CompiledMatch);
66 private StreamReader source = null;
67 private string filename = null;
81 if (reader == null)
throw new ArgumentNullException(
"reader");
91 : this(new StreamReader(filename))
93 this.filename = filename;
98 private GrammarBuilder GetBuilder(ref
int linenum)
103 List<Token> tokens =
new List<Token>();
107 Symbol epsilon = null;
108 while (header && ((line = source.ReadLine()) != null))
113 tokens.AddRange(inputTokenizer.Tokenize(line));
115 if ((tokens.Count == 0) || (tokens[0].Value ==
"#"))
118 if (tokens[0].Type != TokenType.Keyword)
119 { header =
false;
break; }
121 switch(tokens[0].Value)
124 if (root != null)
goto alreadyset;
125 if (tokens.Count != 2)
goto syntaxerr;
127 root =
new Symbol(tokens[1].Value, SymbolType.Nonterminal);
131 if (epsilon != null)
goto alreadyset;
132 if (tokens.Count != 2)
goto syntaxerr;
134 epsilon =
new Symbol(tokens[1].Value, SymbolType.Epsilon);
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));
146 GrammarBuilder builder=
new GrammarBuilder(
147 root ??
new Symbol(Defaults.Root),
148 epsilon ??
new Symbol(Defaults.Epsilon, SymbolType.Epsilon));
150 List<Token> ruletok =
new List<Token>();
151 GrammarEntityParser gep =
new GrammarEntityParser(builder.Epsilon);
153 Action parse = delegate()
155 if (ruletok.Count != 0)
156 foreach (var rule
in gep.ParseMultiRule(ruletok)) builder.AddRule(rule);
162 if ((tokens.Count != 0) && (tokens[0].Value !=
"#"))
164 if (tokens[0].Value !=
"|")
167 ruletok.AddRange(tokens);
172 line = source.ReadLine();
177 tokens.AddRange(inputTokenizer.Tokenize(line));
194 return GetBuilder(ref linenum);
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);
202 throw new FormatException(msg, ex);
208 #region [ IDisposable ]
211 {
if (filename != null) source.Close(); }