Mercury library  1.0
Translation of CFG grammars into an object model (Bachelor's thesis).
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties
Symbol.cs
Go to the documentation of this file.
1 using Mercury.Exceptions;
2 using Mercury.Scanning;
3 using System;
4 
5 namespace Mercury.Syntax
6 {
7 //=============================================================================
8 // Symbol
9 //=============================================================================
10 
15  [Flags]
16  public enum SymbolType
17  {
19  None = 0,
21  Epsilon = 1,
23  Terminal = 2,
25  Nonterminal = 4,
27  Any = Epsilon | Terminal | Nonterminal
28  }
29 
51  public class Symbol : IEquatable<Symbol>, IComparable<Symbol>
52  {
53  //--[ Private methods ]----------------------------------------------
54 
55  private bool IsValid()
56  {
57  return (Type == SymbolType.Epsilon)
58  || (Type == SymbolType.Terminal)
59  || (Type == SymbolType.Nonterminal);
60  }
61 
62  //--[ Constructors ]-------------------------------------------------
63 
65  public Symbol()
66  {
67  Name = Defaults.Epsilon;
68  Type = SymbolType.Epsilon;
69  Token = null;
70  }
71 
77  public Symbol(string name)
79  { }
80 
91  public Symbol(string name, SymbolType type)
92  {
93  if (name == null) throw new ArgumentNullException("name");
94  Type = InferType(name) & type;
95  Name = (Type == SymbolType.Terminal) ? name.ToLower() : name;
96  Token = null;
97 
98  if (!IsValid()) throw new InvalidSymbolException(this);
99  }
100 
110  public Symbol(Token token)
111  {
112  if (token == null) throw new ArgumentNullException("token");
113 
114  Token = token;
115  Name = token.Value.ToLowerInvariant();
116  Type = InferType(Name) & SymbolType.Terminal;
117 
118  if (!IsValid()) throw new InvalidSymbolException(this);
119  }
120 
121  //--[ Methods ]------------------------------------------------------
122 
133  public static SymbolType InferType(string name)
134  {
135  // reject empty name
136  if (string.IsNullOrEmpty(name)) return SymbolType.None;
137 
138  // some cool flags for convenience
139  bool anyLetter = false;
140  bool allLetDig = true;
141  bool allLetDigEx = true;
142  bool allDigits = true;
143  int dotcount = 0;
144 
145  // reject name containing special characters or separators
146  // meanwhile compute predicate values
147  for (int ix = 0; ix < name.Length; ++ix )
148  {
149  char c = name[ix];
150  if (char.IsControl(c) || char.IsSeparator(c)) return SymbolType.None;
151  if (c == '.') ++dotcount;
152 
153  anyLetter |= char.IsLetter(c);
154  allDigits &= (char.IsDigit(c) || (dotcount == 1) || ((ix == 0) && ("+-".IndexOf(c) != -1)));
155  allLetDig &= char.IsLetterOrDigit(c);
156  allLetDigEx &= (char.IsLetterOrDigit(c) || ("@_".IndexOf(c) != -1));
157  }
158 
159  // check terminal b) condition
160  if ((dotcount <= 1) && allDigits && (name[name.Length - 1] != '.'))
161  return SymbolType.Terminal;
162 
163  // check terminal c) condition
164  if ((name.Length == 1) && (!char.IsLetterOrDigit(name[0])))
165  return SymbolType.Terminal;
166 
167  // check terminal a) condition (= epsilon condition)
168  if (allLetDig && (char.IsLower(name[0]) || char.IsDigit(name[0])))
169  return SymbolType.Epsilon | SymbolType.Terminal;
170 
171  // check nonterminal condition
172  if (allLetDigEx && anyLetter && (char.IsUpper(name[0]) || ("@_".IndexOf(name[0]) != -1)))
173  return SymbolType.Nonterminal;
174 
175  // no condition holds, give up
176  return SymbolType.None;
177  }
178 
179  //--[ Properties ]---------------------------------------------------
180 
183  public string Name { get; protected set; }
184 
187  public SymbolType Type { get; protected set; }
188 
191  public bool IsEpsilon { get { return Type == SymbolType.Epsilon; } }
192 
197  public Token Token { get; protected set; }
198 
199  //--[ Overriden methods ]--------------------------------------------
200 
201  #region [ Object ]
202 
203  public override bool Equals(object obj)
204  {
205  Symbol other = obj as Symbol;
206  return other == null ? false : Equals(other);
207  }
208 
209  public override int GetHashCode()
210  { return Name.GetHashCode(); }
211 
212  public override string ToString()
213  {
214  var src = Token == null ? Name : Token.Value;
215 
216  return ((src.Length == 1)
217  && !char.IsLetterOrDigit(src[0])
218  && (Defaults.alphastr.IndexOf(src[0]) == -1))
219  ? "'" + src.ToString() + "'" : src.ToString();
220  }
221 
222  #endregion
223 
224  //--[ Interface implementation ]-------------------------------------
225 
226  #region [ IEquatable ]
227 
228  public bool Equals(Symbol other)
229  { return (other != null) && Name.Equals(other.Name); }
230 
231  #endregion
232 
233  #region [ IComparable ]
234 
235  public int CompareTo(Symbol other)
236  { return Name.CompareTo(other.Name); }
237 
238  #endregion
239 
240  }
241 }
override string ToString()
Definition: Token.cs:75
Token, a part of an input text recognized by tokenizer
Definition: Token.cs:29
override int GetHashCode()
Definition: Symbol.cs:209
Symbol()
Creates an epsilon symbol.
Definition: Symbol.cs:65
A nonterminal symbol.
int CompareTo(Symbol other)
Definition: Symbol.cs:235
SymbolType
Represents a type of symbol. Implemented as Flags since Symbol type inference is ambiguous.
Definition: Symbol.cs:16
static SymbolType InferType(string name)
Infers the type of symbol according to conditions described in the constructor documentation.
Definition: Symbol.cs:133
bool Equals(Symbol other)
Definition: Symbol.cs:228
Symbol(string name)
Creates a new symbol and infers its type. If the constructor does not throw any exception, the symbol is guaranteed to be valid.
Definition: Symbol.cs:77
static string Epsilon
Default epsilon symbol name
Definition: Defaults.cs:50
Symbol(Token token)
Creates a new terminal symbol from a token. If the constructor does not throw any exception...
Definition: Symbol.cs:110
The epsilon symbol.
A terminal symbol.
override bool Equals(object obj)
Definition: Symbol.cs:203
An exception thrown when attempting to create an invalid Mercury.Syntax.Symbol instance.
Symbol(string name, SymbolType type)
Creates a new symbol with desired type. If the constructor does not throw any exception, the symbol is guaranteed to be valid.
Definition: Symbol.cs:91
Represents a single symbol of the grammar. This is an immutable class. For a symbol name to be val...
Definition: Symbol.cs:51
No failure
override string ToString()
Definition: Symbol.cs:212