namespace Parsley { using System.Collections.Generic; public delegate Parser ExtendParserBuilder(T left); public delegate T AtomNodeBuilder(Token atom); public delegate T UnaryNodeBuilder(Token symbol, T operand); public delegate T BinaryNodeBuilder(T left, Token symbol, T right); public enum Associativity { Left, Right } public class OperatorPrecedenceParser : Grammar, Parser { private readonly IDictionary> unitParsers; private readonly IDictionary> extendParsers; private readonly IDictionary extendParserPrecedence; public OperatorPrecedenceParser() { unitParsers = new Dictionary>(); extendParsers = new Dictionary>(); extendParserPrecedence = new Dictionary(); } public void Unit(TokenKind kind, Parser unitParser) { unitParsers[kind] = unitParser; } public void Atom(TokenKind kind, AtomNodeBuilder createAtomNode) { Unit(kind, from token in Token(kind) select createAtomNode(token)); } public void Prefix(TokenKind operation, int precedence, UnaryNodeBuilder createUnaryNode) { Unit(operation, from symbol in Token(operation) from operand in OperandAtPrecedenceLevel(precedence) select createUnaryNode(symbol, operand)); } public void Extend(TokenKind operation, int precedence, ExtendParserBuilder createExtendParser) { extendParsers[operation] = createExtendParser; extendParserPrecedence[operation] = precedence; } public void Postfix(TokenKind operation, int precedence, UnaryNodeBuilder createUnaryNode) { Extend(operation, precedence, left => from symbol in Token(operation) select createUnaryNode(symbol, left)); } public void Binary(TokenKind operation, int precedence, BinaryNodeBuilder createBinaryNode, Associativity associativity = Associativity.Left) { int rightOperandPrecedence = precedence; if (associativity == Associativity.Right) rightOperandPrecedence = precedence - 1; Extend(operation, precedence, left => from symbol in Token(operation) from right in OperandAtPrecedenceLevel(rightOperandPrecedence) select createBinaryNode(left, symbol, right)); } public Reply Parse(TokenStream tokens) { return Parse(tokens, 0); } private Parser OperandAtPrecedenceLevel(int precedence) { return new LambdaParser(tokens => Parse(tokens, precedence)); } private Reply Parse(TokenStream tokens, int precedence) { var token = tokens.Current; if (!unitParsers.ContainsKey(token.Kind)) return new Error(tokens, ErrorMessage.Unknown()); var reply = unitParsers[token.Kind].Parse(tokens); if (!reply.Success) return reply; tokens = reply.UnparsedTokens; token = tokens.Current; while (precedence < GetPrecedence(token)) { //Continue parsing at this precedence level. reply = extendParsers[token.Kind](reply.Value).Parse(tokens); if (!reply.Success) return reply; tokens = reply.UnparsedTokens; token = tokens.Current; } return reply; } private int GetPrecedence(Token token) { var kind = token.Kind; if (extendParserPrecedence.ContainsKey(kind)) return extendParserPrecedence[kind]; return 0; } } }