Given a language, the Interpreter design pattern defines a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
C# code examples of the Interpreter design pattern is provided in 3 forms:
A visualization of the classes and objects participating in this pattern.
The classes and objects participating in this pattern include:
Expression
)
ThousandExpression,
HundredExpression, TenExpression, OneExpression
)
Context
)
InterpreterApp
)
This structural code demonstrates the Interpreter patterns, which using a defined grammer, provides the interpreter that processes parsed statements.
using System;
using System.Collections.Generic;
namespace Interpreter.Structural
{
/// <summary>
/// Interpreter Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
Context context = new Context();
// Usually a tree
List<AbstractExpression> list = new List<AbstractExpression>();
// Populate 'abstract syntax tree'
list.Add(new TerminalExpression());
list.Add(new NonterminalExpression());
list.Add(new TerminalExpression());
list.Add(new TerminalExpression());
// Interpret
foreach (AbstractExpression exp in list)
{
exp.Interpret(context);
}
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Context' class
/// </summary>
public class Context
{
}
/// <summary>
/// The 'AbstractExpression' abstract class
/// </summary>
public abstract class AbstractExpression
{
public abstract void Interpret(Context context);
}
/// <summary>
/// The 'TerminalExpression' class
/// </summary>
public class TerminalExpression : AbstractExpression
{
public override void Interpret(Context context)
{
Console.WriteLine("Called Terminal.Interpret()");
}
}
/// <summary>
/// The 'NonterminalExpression' class
/// </summary>
public class NonterminalExpression : AbstractExpression
{
public override void Interpret(Context context)
{
Console.WriteLine("Called Nonterminal.Interpret()");
}
}
}
This real-world code demonstrates the Interpreter pattern which is used to convert a Roman numeral to a decimal.
This is a placeholder code. To be replaced.using System;
using System.Collections.Generic;
namespace Interpreter.RealWorld
{
/// <summary>
/// Interpreter Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
string roman = "MCMXXVIII";
Context context = new Context(roman);
// Build the 'parse tree'
List<Expression> tree = new List<Expression>();
tree.Add(new ThousandExpression());
tree.Add(new HundredExpression());
tree.Add(new TenExpression());
tree.Add(new OneExpression());
// Interpret
foreach (Expression exp in tree)
{
exp.Interpret(context);
}
Console.WriteLine("{0} = {1}",
roman, context.Output);
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Context' class
/// </summary>
public class Context
{
string input;
int output;
// Constructor
public Context(string input)
{
this.input = input;
}
public string Input
{
get { return input; }
set { input = value; }
}
public int Output
{
get { return output; }
set { output = value; }
}
}
/// <summary>
/// The 'AbstractExpression' class
/// </summary>
public abstract class Expression
{
public void Interpret(Context context)
{
if (context.Input.Length == 0)
return;
if (context.Input.StartsWith(Nine()))
{
context.Output += (9 * Multiplier());
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Four()))
{
context.Output += (4 * Multiplier());
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Five()))
{
context.Output += (5 * Multiplier());
context.Input = context.Input.Substring(1);
}
while (context.Input.StartsWith(One()))
{
context.Output += (1 * Multiplier());
context.Input = context.Input.Substring(1);
}
}
public abstract string One();
public abstract string Four();
public abstract string Five();
public abstract string Nine();
public abstract int Multiplier();
}
/// <summary>
/// A 'TerminalExpression' class
/// <remarks>
/// Thousand checks for the Roman Numeral M
/// </remarks>
/// </summary>
public class ThousandExpression : Expression
{
public override string One() { return "M"; }
public override string Four() { return " "; }
public override string Five() { return " "; }
public override string Nine() { return " "; }
public override int Multiplier() { return 1000; }
}
/// <summary>
/// A 'TerminalExpression' class
/// <remarks>
/// Hundred checks C, CD, D or CM
/// </remarks>
/// </summary>
public class HundredExpression : Expression
{
public override string One() { return "C"; }
public override string Four() { return "CD"; }
public override string Five() { return "D"; }
public override string Nine() { return "CM"; }
public override int Multiplier() { return 100; }
}
/// <summary>
/// A 'TerminalExpression' class
/// <remarks>
/// Ten checks for X, XL, L and XC
/// </remarks>
/// </summary>
public class TenExpression : Expression
{
public override string One() { return "X"; }
public override string Four() { return "XL"; }
public override string Five() { return "L"; }
public override string Nine() { return "XC"; }
public override int Multiplier() { return 10; }
}
/// <summary>
/// A 'TerminalExpression' class
/// <remarks>
/// One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
/// </remarks>
/// </summary>
public class OneExpression : Expression
{
public override string One() { return "I"; }
public override string Four() { return "IV"; }
public override string Five() { return "V"; }
public override string Nine() { return "IX"; }
public override int Multiplier() { return 1; }
}
}
The .NET optimized code demonstrates the same code as above but uses
more modern C# and .NET features.
Here is an elegant C# Interpreter solution.
namespace Interpreter.NetOptimized;
using static System.Console;
using System.Collections.Generic;
/// <summary>
/// Interpreter Design Pattern
/// </summary>
public class Program
{
public static void Main()
{
// Construct the 'parse tree'
List<Expression> tree = [ new ThousandExpression(), new HundredExpression(),
new TenExpression(), new OneExpression() ];
// Create the context (i.e. roman value)
var roman = "MCMXXVIII";
var context = new Context { Input = roman };
// Interpret
tree.ForEach(e => e.Interpret(context));
WriteLine($"{roman} = {context.Output}");
// Wait for user
ReadKey();
}
}
/// <summary>
/// The 'Context' class
/// </summary>
public record Context
{
public string Input { get; set; } = null!;
public int Output { get; set; }
}
/// <summary>
/// The 'AbstractExpression' abstract class
/// </summary>
public abstract class Expression
{
public void Interpret(Context context)
{
if (context.Input.Length == 0)
return;
if (context.Input.StartsWith(Nine()))
{
context.Output += (9 * Multiplier());
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Four()))
{
context.Output += (4 * Multiplier());
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Five()))
{
context.Output += (5 * Multiplier());
context.Input = context.Input.Substring(1);
}
while (context.Input.StartsWith(One()))
{
context.Output += (1 * Multiplier());
context.Input = context.Input.Substring(1);
}
}
public abstract string One();
public abstract string Four();
public abstract string Five();
public abstract string Nine();
public abstract int Multiplier();
}
/// <summary>
/// A 'TerminalExpression' class
/// <remarks>
/// Thousand checks for the Roman Numeral M
/// </remarks>
/// </summary>
public class ThousandExpression : Expression
{
public override string One() => "M";
public override string Four() => " ";
public override string Five() => " ";
public override string Nine() => " ";
public override int Multiplier() => 1000;
}
/// <summary>
/// A 'TerminalExpression' class
/// <remarks>
/// Hundred checks C, CD, D or CM
/// </remarks>
/// </summary>
public class HundredExpression : Expression
{
public override string One() => "C";
public override string Four() => "CD";
public override string Five() => "D";
public override string Nine() => "CM";
public override int Multiplier() => 100;
}
/// <summary>
/// A 'TerminalExpression' class
/// <remarks>
/// Ten checks for X, XL, L and XC
/// </remarks>
/// </summary>
public class TenExpression : Expression
{
public override string One() => "X";
public override string Four() => "XL";
public override string Five() => "L";
public override string Nine() => "XC";
public override int Multiplier() => 10;
}
/// <summary>
/// A 'TerminalExpression' class
/// <remarks>
/// One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
/// </remarks>
/// </summary>
public class OneExpression : Expression
{
public override string One() => "I";
public override string Four() => "IV";
public override string Five() => "V";
public override string Nine() => "IX";
public override int Multiplier() => 1;
}