给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
声明执行操作的接口
实现与语法中的终止符号相关联的“解释”操作。
句子中的每个终端符号都需要一个实例。
每个规则R::= R1R2… 语法中的Rn
维护从R1到Rn的每个符号的AbstractExpression类型的实例变量。
为语法中的非终结符实现一个“解释”操作。 Interpret通常在表示R1到Rn的变量上递归地调用自己。
包含解释器的全局信息
构建(或给出)一个抽象语法树,表示该语法定义的语言中的特定句子。
抽象语法树是由NonterminalExpression和TerminalExpression类的实例组装而成的,调用Interpret操作
using UnityEngine;
using System.Collections;
public class InterpreterStructrue : MonoBehaviour
{
void Start ( )
{
Context context = new Context();
// Usually a tree
ArrayList list = new ArrayList();
// 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);
}
}
}
///
/// The 'Context' class
///
class Context
{
}
///
/// The 'AbstractExpression' abstract class
///
abstract class AbstractExpression
{
public abstract void Interpret(Context context);
}
///
/// The 'TerminalExpression' class
///
class TerminalExpression : AbstractExpression
{
public override void Interpret(Context context)
{
Debug.Log("Called Terminal.Interpret()");
}
}
///
/// The 'NonterminalExpression' class
///
class NonterminalExpression : AbstractExpression
{
public override void Interpret(Context context)
{
Debug.Log("Called Nonterminal.Interpret()");
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//这段代码演示了解释器模式,该模式用于将罗马数字转换为十进制。
namespace InterpreterExample1
{
public class InterpreterExample1 : MonoBehaviour
{
void Start()
{
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);
}
Debug.Log(roman+" = "+ context.Output);
}
}
///
/// The 'Context' class
///
class Context
{
private string _input;
private int _output;
// Constructor
public Context(string input)
{
this._input = input;
}
// Gets or sets input
public string Input
{
get {
return _input; }
set {
_input = value; }
}
// Gets or sets output
public int Output
{
get {
return _output; }
set {
_output = value; }
}
}
///
/// The 'AbstractExpression' class
///
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();
}
///
/// A 'TerminalExpression' class
///
/// Thousand checks for the Roman Numeral M
///
///
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; }
}
///
/// A 'TerminalExpression' class
///
/// Hundred checks C, CD, D or CM
///
///
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; }
}
///
/// A 'TerminalExpression' class
///
/// Ten checks for X, XL, L and XC
///
///
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; }
}
///
/// A 'TerminalExpression' class
///
/// One checks for I, II, III, IV, V, VI, VI, VII, VIII, IX
///
///
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; }
}
}
using System;
using UnityEngine;
using System.Collections;
using System.Globalization;
using System.Reflection;
public class InterpreterExample2 : MonoBehaviour
{
void Start ( )
{
string question1 = "2 Gallons to pints";
AskQuestion(question1);
string question2 = "4 Gallons to tablespoons";
AskQuestion(question2);
}
protected void AskQuestion(string question)
{
ConversionContext context = new ConversionContext(question);
string fromConversion = context.fromConversion; // in this example fromConversion is always the second word
string toConversion = context.toConversion;
double quantity = context.quantity;
// Trying to get a matching class for the word "fromConversion"
try
{
// Getting the type, we also have to define the namespace (in this case InterpreterPattern as defined above)
// and fromConversion should hold the class name (in this case Gallons)
Type type = Type.GetType("InterpreterPattern." + fromConversion);
object instance = Activator.CreateInstance(type);
Expression expression = instance as Expression;
// Get the matching method: e.g. (toConversion = pints)
MethodInfo method = type.GetMethod(toConversion);
string result = (string)method.Invoke(instance, new object[] {
quantity });
Debug.Log("Output: " + quantity.ToString() + " " + fromConversion + " are " + result + " " + toConversion);
}
catch (Exception e)
{
Debug.Log(e.Message);
}
}
}
// Context object that does try to make sense of an input string:
public class ConversionContext
{
public string conversionQues {
get; protected set; }
public string fromConversion {
get; protected set; }
public string toConversion {
get; protected set; }
public double quantity {
get; protected set; }
protected string[] partsOfQues;
// here happens the sensemaking
public ConversionContext(string input)
{
Debug.Log("Input: " + input);
this.conversionQues = input;
this.partsOfQues = input.Split(new string[] {
" " }, System.StringSplitOptions.RemoveEmptyEntries);
if (partsOfQues.Length >= 4)
{
fromConversion = GetCapitalized(partsOfQues[1]);
// 1 gallon to pints
toConversion = GetLowerCase(partsOfQues[3]);
// get quantitiy:
double quant;
double.TryParse(partsOfQues[0], out quant);
this.quantity = quant;
}
}
// Some helper methods:
protected string GetCapitalized(string word)
{
word = word.ToLower();
word = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(word);
// make sure a 's' is appended
if (word.EndsWith("s") == false)
{
word += "s";
}
return word;
}
protected string GetLowerCase(string word)
{
return word.ToLower();
}
}
// Definition of all the things the concrete expression
// shall be able to convert into
public abstract class Expression
{
public abstract string gallons(double quantity);
public abstract string quarts(double quantity);
public abstract string pints(double quantity);
public abstract string cups(double quantity);
public abstract string tablespoons(double quantity);
}
// concrete class
public class Gallons : Expression
{
#region implemented abstract members of Expression
public override string gallons(double quantity)
{
return quantity.ToString();
}
public override string quarts(double quantity)
{
return (quantity * 4).ToString();
}
public override string pints(double quantity)
{
return (quantity * 8).ToString();
}
public override string cups(double quantity)
{
return (quantity * 16).ToString();
}
public override string tablespoons(double quantity)
{
return (quantity * 256).ToString();
}
#endregion
}