典型的には、これは、2つのステップを伴う:字句(字句解析の略)と解析を。
最初の手順では、入力文字列をトークンと呼ばれる語彙項目のシーケンスに変換します。この目的のためには、例えば、トークンの種類ごとに列挙型を宣言することがあります
public enum TokenType
{
OpenParenthesis,
CloseParenthesis,
And,
Or,
Tag
}
とトークンのクラス:
sealed class Token
{
public TokenType Type { get; private set; }
public string Item { get; private set; }
public Token(TokenType type, string item) { Type = type; Item = item; }
}
は今、あなたは入力文字列をオンにするアルゴリズムを記述し、例えばtag-a and (tag-b or tag-c)
を、Token
のインスタンスに変換します。正規表現を使用してさまざまな項目を認識できます。たとえば、@"\s*\(\s*"
は空白を認識するための正規表現になります。完成したシーケンスは次のようになります:
new Token(TokenType.Tag, "tag-a")
new Token(TokenType.And, null)
new Token(TokenType.OpenParenthesis, null)
new Token(TokenType.Tag, "tag-b")
new Token(TokenType.Or, null)
new Token(TokenType.Tag, "tag-c")
new Token(TokenType.CloseParenthesis, null)
このシーケンスを取得したら、パーサーを実行する必要があります。このような式の解析には多くの戦略があります。最初はrecursive descent parserをお勧めします。
あなたは、もちろん、解析ツリーを含むようにいくつかのクラスが必要になります。これがあることを
public static Node ParseExpression(Token[] tok)
{
int i = 0;
return parseExpressionBoolOr(tok, ref i);
}
private static Node parseExpressionBoolOr(Token[] tok, ref int i)
{
var left = parseExpressionBoolAnd(tok, ref i);
while (tok[i].Type == TokenType.Or)
{
i++;
var right = parseExpressionBoolAnd(tok, ref i);
left = new BooleanNode(BooleanOperator.Or, left, right);
}
return left;
}
private static Node parseExpressionBoolAnd(Token[] tok, ref int i)
{
var left = parseExpressionPrimary(tok, ref i);
while (tok[i].Type == TokenType.And)
{
i++;
var right = parseExpressionPrimary(tok, ref i);
left = new BooleanNode(BooleanOperator.And, left, right);
}
return left;
}
private static Node parseExpressionPrimary(Token[] tok, ref int i)
{
if (tok[i].Type == TokenType.OpenParenthesis)
{
i++;
var node = parseExpressionBoolOr(tok, ref i);
if (tok[i].Type != TokenType.CloseParenthesis)
throw new InvalidOperationException(); // or customised parse exception
return node;
}
else if (tok[i].Type == TokenType.Tag)
{
var node = new TagNode(tok[i].Item);
i++;
return node;
}
else
throw new InvalidOperationException(); // or customised parse exception
}
注:その後、
abstract class Node { }
enum BooleanOperator { And, Or }
sealed class BooleanNode : Node
{
public BooleanOperator Operator { get; private set; }
public Node Left { get; private set; }
public Node Right { get; private set; }
public BooleanNode(BooleanOperator op, Node left, Node right)
{
Operator = op;
Left = left;
Right = right;
}
}
sealed class TagNode : Node
{
public string Tag { get; private set; }
public TagNode(string tag) { Tag = tag; }
}
そして、再帰下降構文解析は次のようになります。非常に簡単な例です。ただし、これは最大限の柔軟性があります。このアルゴリズムを拡張して、必要な言語を完全に解析することができます。
これはすばらしい詳細な例です。概念とコードの両方で、さまざまな方法で多くのことを教えてくれました。この宝石をありがとう! – SeanKilleen
[プレザント:]](http://meta.stackexchange.com/questions/700) – Timwi