using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Sloth
{
public class Grammar : List<GrammarRule> { }
public abstract class GrammarRule
{
public Int32 ID { get; set; }
public abstract ParseTreeNode Match(IEnumerable<Token> tokens);
}
public class TokenSequence : GrammarRule
{
public List<TokenType> Constraints { get; private set; }
protected TokenSequence()
{
this.
Constraints = new List
<TokenType
>();
}
public static TokenSequence Create(Int32 id, params TokenType[] tokenConstraints)
{
if (tokenConstraints.Length == 0)
throw new ArgumentException
("At least one token is required to create a rule.");
TokenSequence rule
= new TokenSequence
();
rule.ID = id;
rule.Constraints.AddRange(tokenConstraints);
return rule;
}
public Boolean IsValid(IEnumerable<Token> tokens)
{
IEnumerator<Token> enumerator = tokens.GetEnumerator();
Int32 index = 0;
while (enumerator.MoveNext() && (index < this.Constraints.Count))
{
if (enumerator.Current.Type != this.Constraints[index])
return false;
index++;
}
return (index == this.Constraints.Count);
}
public override ParseTreeNode Match(IEnumerable<Token> tokens)
{
ParseTreeNode result
= new ParseTreeNode
();
result.RuleID = this.ID;
if (!this.IsValid(tokens))
return null;
result.Tokens.AddRange(tokens.Take(this.Constraints.Count));
return result;
}
}
public class RuleSelection : GrammarRule
{
public List<GrammarRule> Alternatives { get; private set; }
protected RuleSelection()
{
this.
Alternatives = new List
<GrammarRule
>();
}
public static RuleSelection Create(Int32 id, params GrammarRule[] possibleRules)
{
if (possibleRules.Length <= 1)
throw new ArgumentException
("At least two rules are needed to create an alternative.");
RuleSelection rule
= new RuleSelection
();
rule.ID = id;
rule.Alternatives.AddRange(possibleRules);
return rule;
}
public override ParseTreeNode Match(IEnumerable<Token> tokens)
{
ParseTreeNode result
= new ParseTreeNode
();
result.RuleID = this.ID;
foreach (GrammarRule rule in this.Alternatives)
{
ParseTreeNode match = rule.Match(tokens);
if (match != null)
{
result.Children.Add(match);
return result;
}
}
return null;
}
}
public class RuleSequence : GrammarRule
{
public List<GrammarRule> Constraints { get; private set; }
protected RuleSequence()
{
this.
Constraints = new List
<GrammarRule
>();
}
public static RuleSequence Create(Int32 id, params GrammarRule[] ruleConstraints)
{
if (ruleConstraints.Length == 0)
throw new ArgumentException
("At least one rule is needed to create a rule.");
RuleSequence rule
= new RuleSequence
();
rule.ID = id;
rule.Constraints.AddRange(ruleConstraints);
return rule;
}
public override ParseTreeNode Match(IEnumerable<Token> tokens)
{
Int32 matchedTokens = 0;
ParseTreeNode result
= new ParseTreeNode
();
result.RuleID = this.ID;
foreach (GrammarRule rule in this.Constraints)
{
ParseTreeNode match = rule.Match(tokens.Skip(matchedTokens));
if (match == null)
return null;
matchedTokens += match.GetTokensCount();
result.Children.Add(match);
}
return result;
}
}
}