笔记 - C#从头开始构建编译器 - 2
视频与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的更多相关文章
- 笔记 - C#从头开始构建编译器 - 1
视频与PR:https://github.com/terrajobst/minsk/blob/master/docs/episode-01.md 作者是 Immo Landwerth(https:// ...
- 笔记 - C#从头开始构建编译器 - 3
视频与PR:https://github.com/terrajobst/minsk/blob/master/docs/episode-03.md 作者是 Immo Landwerth(https:// ...
- keras 学习笔记:从头开始构建网络处理 mnist
全文参考 < 基于 python 的深度学习实战> import numpy as np from keras.datasets import mnist from keras.model ...
- 软工读书笔记 week 9 ——《构建之法》
软工读书笔记 week 9 ——<构建之法> 最近的三周我们正式开始我们的项目.然后我也把<构建之法>中的相关章节再拿出来读了一番.以下是一些 ...
- [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设
[HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设 敲黑板!! <q>元素添加短引用,<blockquote>添加长引用 在段落里添加引用就使用< ...
- blfs(systemd版本)学习笔记-为桌面环境构建xorg服务
我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! lfs准备使用桌面环境,首先需要构建xorg服务 xorg服务项目地址:http://www.linuxfromscratch. ...
- blfs(systemv版本)学习笔记-为桌面环境构建xorg服务
我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! lfs准备使用桌面环境,首先需要构建xorg服务 xorg服务项目地址:http://www.linuxfromscratch. ...
- 软工读书笔记 week 5 ——《构建之法》
本周主要对<构建之法>中的一部分进行阅读. 一.软件与软件工程究竟是什么? 本书的概论部分就指出“软件 = 程序 + 软件工程”.而我们这门课的名字就叫“现代软件工程”.其实在上课之前,我 ...
- 《Maven实战》笔记-10-灵活的构建
一.灵活构建的意义 一个优秀的构建系统必须足够灵活,它应该能够让项目在不同的环境下都能成功地构建.例如,典型的项目都会有开发环境.测试环境和产品环境,这些环境的数据库配置不尽相同,那么项目构建的时候就 ...
随机推荐
- 如何贡献补丁到uboot社区?
答: 首次贡献分为两步: 1. 首先需要订阅一下,地址在此https://lists.denx.de/listinfo/u-boot,使邮箱地址对应有一个成员名称,才能向uboot社区发送补丁,否则会 ...
- Java基础 hello world基础实例
JDK :OpenJDK-11 OS :CentOS 7.6.1810 IDE :Eclipse 2019‑03 typesetting :Markdown code ...
- 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 ...
- ES6深入浅出-5 新版对象-1.如何创建对象
对象属性的加强: 可以通过new Object(), Object.create()方法,或者使用字面量标记(初始化标记)初始化对象. 一个对象初始化器,由花括号/大括号 ({}) 包含的一个由零个或 ...
- Spring Cloud 如何使用Eureka注册服务 4.2.2
要使用Eureka实现服务发现,需要项目中包含Eureka的服务端发现组件以及客户端发现组件. 搭建Maven父工程 创建一个Maven父工程xcservice-springcloud,并在工程的po ...
- pycharm远程SSH调用服务器python解释器教程
该教程主要介绍pycharm远程SSH调用解释器以及建立SFTP文件传输协议: 第一步:建立SSH连接: 第二步:建立SFTP协议: (1)SSH: 配置远程python解释器 这里主要讲的是如何配置 ...
- HTTP请求重复发送
帖子地址 http://bbs.csdn.net/topics/390831787 解决方案:1. java -Dsun.net.http.retryPost=false 2. 换用apche ht ...
- HTML中设置在浏览器中固定位置fixed定位
之前的博文 HTML布局排版之制作个人网站的文章列表,中链接到的文章本身,也需要返回到列表主页,可在每个文章页面加导航条,也可以只加个返回到列表主页的链接.刚开始是想在博文最下方,加个返回文章列表的链 ...
- FreeRTOS 时间片,外部中断,任务优先级的一个疑问
时间片1ms 假设有两个任务,A和B,A任务等待中断里面发出的信号量,B任务在运行 此时,B任务运行了300us的时候中断发生,发出信号量,那么任务A接收到信号量,A任务优先级高,A任务运行 有个问题 ...
- Cas(08)——单点登出
单点登出 目录 1.1 Cas Client端配置单点登出 1.2 Cas Server端禁用单点登出 1.1 Cas Client端配置单点登出 单点登出功能跟单点登录功能是 ...