视频与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。

笔记 - C#从头开始构建编译器 - 2的更多相关文章

  1. 笔记 - C#从头开始构建编译器 - 1

    视频与PR:https://github.com/terrajobst/minsk/blob/master/docs/episode-01.md 作者是 Immo Landwerth(https:// ...

  2. 笔记 - C#从头开始构建编译器 - 3

    视频与PR:https://github.com/terrajobst/minsk/blob/master/docs/episode-03.md 作者是 Immo Landwerth(https:// ...

  3. keras 学习笔记:从头开始构建网络处理 mnist

    全文参考 < 基于 python 的深度学习实战> import numpy as np from keras.datasets import mnist from keras.model ...

  4. 软工读书笔记 week 9 ——《构建之法》

    软工读书笔记  week 9                 ——<构建之法> 最近的三周我们正式开始我们的项目.然后我也把<构建之法>中的相关章节再拿出来读了一番.以下是一些 ...

  5. [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设

    [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设 敲黑板!! <q>元素添加短引用,<blockquote>添加长引用 在段落里添加引用就使用< ...

  6. blfs(systemd版本)学习笔记-为桌面环境构建xorg服务

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! lfs准备使用桌面环境,首先需要构建xorg服务 xorg服务项目地址:http://www.linuxfromscratch. ...

  7. blfs(systemv版本)学习笔记-为桌面环境构建xorg服务

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! lfs准备使用桌面环境,首先需要构建xorg服务 xorg服务项目地址:http://www.linuxfromscratch. ...

  8. 软工读书笔记 week 5 ——《构建之法》

    本周主要对<构建之法>中的一部分进行阅读. 一.软件与软件工程究竟是什么? 本书的概论部分就指出“软件 = 程序 + 软件工程”.而我们这门课的名字就叫“现代软件工程”.其实在上课之前,我 ...

  9. 《Maven实战》笔记-10-灵活的构建

    一.灵活构建的意义 一个优秀的构建系统必须足够灵活,它应该能够让项目在不同的环境下都能成功地构建.例如,典型的项目都会有开发环境.测试环境和产品环境,这些环境的数据库配置不尽相同,那么项目构建的时候就 ...

随机推荐

  1. 如何贡献补丁到uboot社区?

    答: 首次贡献分为两步: 1. 首先需要订阅一下,地址在此https://lists.denx.de/listinfo/u-boot,使邮箱地址对应有一个成员名称,才能向uboot社区发送补丁,否则会 ...

  2. Java基础 hello world基础实例

        JDK :OpenJDK-11      OS :CentOS 7.6.1810      IDE :Eclipse 2019‑03 typesetting :Markdown   code ...

  3. linux(centos7.0以上版本)安装 mysql-5.7.24-linux-glibc2.12-x86_64.tar 版本的mysql

      1:查看 linux下是否有老版本的mysql(有删除) 查找old mysql:rpm -qa | grep mysql 卸载:卸载命令:rpm –ev {包名}——:rpm -ev mysql ...

  4. ES6深入浅出-5 新版对象-1.如何创建对象

    对象属性的加强: 可以通过new Object(), Object.create()方法,或者使用字面量标记(初始化标记)初始化对象. 一个对象初始化器,由花括号/大括号 ({}) 包含的一个由零个或 ...

  5. Spring Cloud 如何使用Eureka注册服务 4.2.2

    要使用Eureka实现服务发现,需要项目中包含Eureka的服务端发现组件以及客户端发现组件. 搭建Maven父工程 创建一个Maven父工程xcservice-springcloud,并在工程的po ...

  6. pycharm远程SSH调用服务器python解释器教程

    该教程主要介绍pycharm远程SSH调用解释器以及建立SFTP文件传输协议: 第一步:建立SSH连接: 第二步:建立SFTP协议: (1)SSH: 配置远程python解释器 这里主要讲的是如何配置 ...

  7. HTTP请求重复发送

    帖子地址 http://bbs.csdn.net/topics/390831787 解决方案:1.  java -Dsun.net.http.retryPost=false 2. 换用apche ht ...

  8. HTML中设置在浏览器中固定位置fixed定位

    之前的博文 HTML布局排版之制作个人网站的文章列表,中链接到的文章本身,也需要返回到列表主页,可在每个文章页面加导航条,也可以只加个返回到列表主页的链接.刚开始是想在博文最下方,加个返回文章列表的链 ...

  9. FreeRTOS 时间片,外部中断,任务优先级的一个疑问

    时间片1ms 假设有两个任务,A和B,A任务等待中断里面发出的信号量,B任务在运行 此时,B任务运行了300us的时候中断发生,发出信号量,那么任务A接收到信号量,A任务优先级高,A任务运行 有个问题 ...

  10. Cas(08)——单点登出

    单点登出 目录 1.1     Cas Client端配置单点登出 1.2     Cas Server端禁用单点登出 1.1     Cas Client端配置单点登出 单点登出功能跟单点登录功能是 ...