笔记 - 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-灵活的构建
一.灵活构建的意义 一个优秀的构建系统必须足够灵活,它应该能够让项目在不同的环境下都能成功地构建.例如,典型的项目都会有开发环境.测试环境和产品环境,这些环境的数据库配置不尽相同,那么项目构建的时候就 ...
随机推荐
- Xamarin图表开发基础教程(1)
Xamarin图表开发基础教程(1) 在Xamarin图表开发中,最常用的框架是OxyPlot和Microcharts.其中,OxyOPlot提供多种多样的图表类型和丰富的图表功能,可以实现各种复杂的 ...
- 【转】Python 代码批量抓取免费高清图片!
import requests from bs4 import BeautifulSoup import random import time from fake_useragent import U ...
- C++ 11 线程调用类的成员函数解决办法
在C++中,_beginthreadex 创建线程是很麻烦的.要求入口函数必须是类的静态函数. 通常,可以采用thunk,或者模板来实现. 因C++ 11中引入了 std::async ,可以很好的解 ...
- spring 装配bean的混合使用
在现实中,使用XML或者注解各有道理,建议在自己的工程中所开发的类尽量使用注解方式,因为使用它并不困难,甚至可以说更为简单,而对于引入第三方包或者服务的类,尽量使用XML方式,这样的好处是可以尽量对三 ...
- 小程序报错 thirdScriptError
thirdScriptError sdk uncaught third Error Unexpected token export SyntaxError: Unexpected token expo ...
- filebeat输出到kafka
# cat filebeat.yml filebeat.inputs: - type: log enabled: true tail_files: true paths: - /data/www.ex ...
- Andrew Ng机器学习课程7
回顾 通过定义训练集S={(x(i),y(i));i=1,2,...,m}与线性决策平面(w,b)之间的function margin γ^和geometric margin γ .好的分类决策平面特 ...
- 探索安卓热修复框架AndFix的奥秘
虽然阿里的AndFix框架已经出来很长时间了,但是还不了解它的同学依然挺多,接下来就跟着我一起来到AndFix的世界里一起看看,如何达到不用重新安装app就可以修复bug. 1.什么是AndFix? ...
- 数据恢复方法--linux ubuntu--ddrescue
live cd:可以让Linux系统从光盘启动,用户可以方便的先对系统进行一次体验,觉得好用,再进行硬盘安装.ubuntu live cd版:就是可以直接光盘启动的ubuntu系统.Mr. Hou先让 ...
- CentOS7服务器查看相关配置命令
CPU个数:(base) [jiangshan@localhost ~]$ grep 'physical id' /proc/cpuinfo | sort -u | wc -l2CPU核数:(base ...