视频与PR:https://github.com/terrajobst/minsk/blob/master/docs/episode-02.md
作者是 Immo Landwerth(https://twitter.com/terrajobst),微软 .NET 团队的项目经理。
这一集的主要内容:
1.添加 Binder,充当语义分析作用。
Binder 基于 SyntaxTree,大体上 SyntaxKind.XXX_Expression => Bind_XXX_Expression。
在 SyntaxTree 中,运算符只是个枚举值(即也就只是个符号),而在 Binder 中必须赋予更加具体的语义。
比如:
> SyntaxKind.PlusToken => BoundBinaryOperatorKind.Addition (“+”代表累加)
> SyntaxKind.AmpersandAmpersandToken => BoundBinaryOperatorKind.LogicalAnd(“&&”代表逻辑与)
在 Binder 中,运算符有更加宽泛的含义,如果是二元运算符,必须可以获取其符号的 SyntaxKind、BoundBinaryOperatorKind、LeftType、RightType、ResultType。计算结果的类型代表了该二元表达式的类型。
以 BoundBinaryOperator 作为具体实现:
using System; using Minsk.CodeAnalysis.Syntax; namespace Minsk.CodeAnalysis.Binding { internal sealed class BoundBinaryOperator { private BoundBinaryOperator(SyntaxKind syntaxKind, BoundBinaryOperatorKind kind, Type type) : this(syntaxKind, kind, type, type, type) { } private BoundBinaryOperator(SyntaxKind syntaxKind, BoundBinaryOperatorKind kind, Type operandType, Type resultType) : this(syntaxKind, kind, operandType, operandType, resultType) { } private BoundBinaryOperator(SyntaxKind syntaxKind, BoundBinaryOperatorKind kind, Type leftType, Type rightType, Type resultType) { SyntaxKind = syntaxKind; Kind = kind; LeftType = leftType; RightType = rightType; Type = resultType; } public SyntaxKind SyntaxKind { get; } public BoundBinaryOperatorKind Kind { get; } public Type LeftType { get; } public Type RightType { get; } public Type Type { get; } private static BoundBinaryOperator[] _operators = { new BoundBinaryOperator(SyntaxKind.PlusToken, BoundBinaryOperatorKind.Addition, typeof(int)), new BoundBinaryOperator(SyntaxKind.MinusToekn, BoundBinaryOperatorKind.Subtraction, typeof(int)), new BoundBinaryOperator(SyntaxKind.StarToken, BoundBinaryOperatorKind.Multiplication, typeof(int)), new BoundBinaryOperator(SyntaxKind.SlashToken, BoundBinaryOperatorKind.Division, typeof(int)), new BoundBinaryOperator(SyntaxKind.EqualsEqualsToken, BoundBinaryOperatorKind.Equals, typeof(int), typeof(bool)), new BoundBinaryOperator(SyntaxKind.BangEqualsToken, BoundBinaryOperatorKind.NotEquals, typeof(int), typeof(bool)), new BoundBinaryOperator(SyntaxKind.AmpersandAmpersandToken, BoundBinaryOperatorKind.LogicalAnd, typeof(bool)), new BoundBinaryOperator(SyntaxKind.PipePipeToken, BoundBinaryOperatorKind.LogicalOr, typeof(bool)), new BoundBinaryOperator(SyntaxKind.EqualsEqualsToken, BoundBinaryOperatorKind.Equals, typeof(bool)), new BoundBinaryOperator(SyntaxKind.BangEqualsToken, BoundBinaryOperatorKind.NotEquals, typeof(bool)), }; public static BoundBinaryOperator Bind(SyntaxKind syntaxKind, Type leftType, Type rightType) { foreach (var op in _operators) { if (op.SyntaxKind == syntaxKind && op.LeftType == leftType && op.RightType == rightType) return op; } return null; } } }
以及 BoundBinaryExpression 的实现:
using System; namespace Minsk.CodeAnalysis.Binding { internal sealed class BoundBinaryExpression : BoundExpression { public BoundBinaryExpression(BoundExpression left, BoundBinaryOperator op, BoundExpression right) { Left = left; Op = op; Right = right; } public override Type Type => Op.Type; public override BoundNodeKind Kind => BoundNodeKind.BinaryExpression; public BoundExpression Left { get; } public BoundBinaryOperator Op { get; } public BoundExpression Right { get; } } }
2.Evaluator 不再基于 SyntaxTree 求值,而是基于 Binder 求值。
3.优先级更加通用的做法。
namespace Minsk.CodeAnalysis.Syntax { internal static class SyntaxFacts { public static int GetUnaryOperatorPrecedence(this SyntaxKind kind) { switch (kind) { case SyntaxKind.PlusToken: case SyntaxKind.MinusToekn: case SyntaxKind.BangToken: return 6; default: return 0; } } public static int GetBinaryOperatorPrecedence(this SyntaxKind kind) { switch (kind) { case SyntaxKind.StarToken: case SyntaxKind.SlashToken: return 5; case SyntaxKind.PlusToken: case SyntaxKind.MinusToekn: return 4; case SyntaxKind.EqualsEqualsToken: case SyntaxKind.BangEqualsToken: return 3; case SyntaxKind.AmpersandAmpersandToken: return 2; case SyntaxKind.PipePipeToken: return 1; default: return 0; } } internal static SyntaxKind GetKeyWordKind(string text) { switch (text) { case "true": return SyntaxKind.TrueKeyword; case "false": return SyntaxKind.FalseKeyword; default: return SyntaxKind.IdentifierToken; } } } }
结合优先级可以更加深刻理解递归下降分析的思路。
4.实现了 Boolean 类型,以及其他的运算符。
C#语言点:
1.扩展方法。将 this XXX 作为 static 函数的第一个成员,然后该函数成为 XXX 的成员函数。这也是一般意义上实现类成员函数的方法。
2.库函数
public static class Enumerable { public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second); }
在System.Linq中,库为 Enumerable 扩展了很多方法,见第一点。
工具:
VS的代码转换技巧,比如快速对逻辑表达式取反、快速将 if 转为 switch。
原文:https://www.cnblogs.com/wqyu/p/10815398.html