视频与PR:https://github.com/terrajobst/minsk/blob/master/docs/episode-03.md

作者是 Immo Landwerth(https://twitter.com/terrajobst),微软 .NET 团队的项目经理。

这一集前半段主要是重构代码,后半段的主要内容:

1. 变量与赋值表达式

2. 加强诊断信息

Parser 非常清晰

using System.Collections.Generic;

namespace Minsk.CodeAnalysis.Syntax
{
internal sealed class Parser
{
private readonly SyntaxToken[] _tokens;
private int _position;
private DiagnosticBag _diagnostics = new DiagnosticBag(); public Parser(string text)
{
var tokens = new List<SyntaxToken>(); var lexer = new Lexer(text);
SyntaxToken token;
do
{
token = lexer.Lex();
if (token.Kind != SyntaxKind.WhiteSpaceToken && token.Kind != SyntaxKind.BadToken)
tokens.Add(token);
} while (token.Kind != SyntaxKind.EndOfFileToken); _tokens = tokens.ToArray();
_diagnostics.AddRange(lexer.Diagnostics);
} public DiagnosticBag Diagnostics => _diagnostics; private SyntaxToken Peek(int offset)
{
var index = _position + offset;
if (index >= _tokens.Length)
return _tokens[_tokens.Length - 1];
return _tokens[index];
} private SyntaxToken Current => Peek(0); private SyntaxToken NextToken()
{
var token = Current;
_position++;
return token;
} private SyntaxToken MatchToken(SyntaxKind kind)
{
if (Current.Kind == kind)
return NextToken(); _diagnostics.ReportUnexpectedToken(Current.Span, Current.Kind, kind);
return new SyntaxToken(kind, Current.Position, null, null);
} public SyntaxTree Parse()
{
var expression = ParseExpression();
var endOfFileToken = MatchToken(SyntaxKind.EndOfFileToken);
return new SyntaxTree(_diagnostics, expression, endOfFileToken);
} private ExpressionSyntax ParseExpression()
{
return ParseAssignmentExpression();
} private ExpressionSyntax ParseAssignmentExpression()
{
if (Peek(0).Kind == SyntaxKind.IdentifierToken && Peek(1).Kind == SyntaxKind.EqualsToken)
{
var identifierToken = NextToken();
var equalsToken = NextToken();
var right = ParseAssignmentExpression();
return new AssignmentExpressionSyntax(identifierToken, equalsToken, right);
} return ParseBinaryExpression();
} private ExpressionSyntax ParseBinaryExpression(int parentPrecedence = 0)
{
ExpressionSyntax left;
var unaryOperatorPrecedence = Current.Kind.GetUnaryOperatorPrecedence();
if (unaryOperatorPrecedence != 0 && unaryOperatorPrecedence >= parentPrecedence)
{
var operatorToken = NextToken();
var operand = ParseBinaryExpression(unaryOperatorPrecedence);
left = new UnaryExpressionSyntax(operatorToken, operand);
}
else
left = ParsePrimaryExpression(); while (true)
{
var precedence = Current.Kind.GetBinaryOperatorPrecedence();
if (precedence == 0 || precedence <= parentPrecedence)
break; var operatorToken = NextToken();
var right = ParseBinaryExpression(precedence);
left = new BinaryExpressionSyntax(left, operatorToken, right);
} return left;
} private ExpressionSyntax ParsePrimaryExpression()
{
switch (Current.Kind)
{
case SyntaxKind.OpenParenthesisToken:
{
var left = NextToken();
var expression = ParseExpression();
var right = MatchToken(SyntaxKind.CloseParenthesisToken);
return new ParenthesizedExpressionSyntax(left, expression, right);
} case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
{
var keywordToken = NextToken();
var value = keywordToken.Kind == SyntaxKind.TrueKeyword;
return new LiteralExpressionSyntax(keywordToken, value);
} case SyntaxKind.IdentifierToken:
{
var identifierToken = NextToken();
return new NameExpressionSyntax(identifierToken);
} default:
{
var numberToken = MatchToken(SyntaxKind.NumberToken);
return new LiteralExpressionSyntax(numberToken);
}
} }
}
}

作为语义分析的 Binder 也非常清晰

using System;
using System.Collections.Generic;
using System.Linq;
using Minsk.CodeAnalysis.Syntax; namespace Minsk.CodeAnalysis.Binding
{
internal sealed class Binder
{
private readonly DiagnosticBag _diagnostics = new DiagnosticBag ();
private readonly Dictionary<VariableSymbol, object> _variables; public Binder(Dictionary<VariableSymbol, object> variables)
{
_variables = variables;
} public DiagnosticBag Diagnostics => _diagnostics; public BoundExpression BindExpression(ExpressionSyntax syntax)
{
switch (syntax.Kind)
{
case SyntaxKind.ParenthesizedExpression:
return BindParenthesizedExpression((ParenthesizedExpressionSyntax)syntax);
case SyntaxKind.LiteralExpression:
return BindLiteralExpression((LiteralExpressionSyntax)syntax);
case SyntaxKind.NameExpression:
return BindNameExpression((NameExpressionSyntax)syntax);
case SyntaxKind.AssignmentExpression:
return BindAssignmentExpression((AssignmentExpressionSyntax)syntax);
case SyntaxKind.UnaryExpression:
return BindUnaryExpression((UnaryExpressionSyntax)syntax);
case SyntaxKind.BinaryExpression:
return BindBinaryExpression((BinaryExpressionSyntax)syntax);
default:
throw new Exception($"Unexpected syntax {syntax.Kind}");
}
} private BoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntax syntax)
{
return BindExpression(syntax.Expression);
} private BoundExpression BindLiteralExpression(LiteralExpressionSyntax syntax)
{
var value = syntax.Value ?? 0;
return new BoundLiteralExpression(value);
} private BoundExpression BindNameExpression(NameExpressionSyntax syntax)
{
var name = syntax.IdentifierToken.Text;
var variable = _variables.Keys.FirstOrDefault(v => v.Name == name);
if (variable == null)
{
_diagnostics.ReportUndefinedName(syntax.IdentifierToken.Span, name);
return new BoundLiteralExpression(0);
} return new BoundVariableExpression(variable);
} private BoundExpression BindAssignmentExpression(AssignmentExpressionSyntax syntax)
{
var name = syntax.IdentifierToken.Text;
var boundExpression = BindExpression(syntax.Expression); var existingVariable = _variables.Keys.FirstOrDefault(v => v.Name == name);
if (existingVariable != null)
_variables.Remove(existingVariable); var variable = new VariableSymbol(name, boundExpression.Type);
_variables[variable] = null; return new BoundAssignmentExpression(variable, boundExpression);
} private BoundExpression BindUnaryExpression(UnaryExpressionSyntax syntax)
{
var boundOperand = BindExpression(syntax.Operand);
var boundOperator = BoundUnaryOperator.Bind(syntax.OperatorToken.Kind, boundOperand.Type);
if (boundOperator == null)
{
_diagnostics.ReportUndefinedUnaryOperator(syntax.OperatorToken.Span, syntax.OperatorToken.Text, boundOperand.Type);
return boundOperand;
}
return new BoundUnaryExpression(boundOperator, boundOperand);
} private BoundExpression BindBinaryExpression(BinaryExpressionSyntax syntax)
{
var boundLeft = BindExpression(syntax.Left);
var boundRight = BindExpression(syntax.Right);
var boundOperator = BoundBinaryOperator.Bind(syntax.OperatorToken.Kind, boundLeft.Type, boundRight.Type);
if (boundOperator == null)
{
_diagnostics.ReportUndefinedBinaryOperator(syntax.OperatorToken.Span, syntax.OperatorToken.Text, boundLeft.Type, boundRight.Type);
return boundLeft;
}
return new BoundBinaryExpression(boundLeft, boundOperator, boundRight);
}
}
}

C#语言点:

public static class Enumerable
{
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
}

FirstOrDefault 可以使用谓词作为判断条件,Binder 的 55 行使用了 Lambda 表达式。

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

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

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

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

    视频与PR:https://github.com/terrajobst/minsk/blob/master/docs/episode-01.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. Flutter移动电商实战 --(48)详细页_详情和评论的切换

    增加切换的效果,我们主要是修改这个地方 这样我们的评论的内容就显示出来了 最终代码 details_web.dart import 'package:flutter/material.dart'; i ...

  2. npm package.json配置整理

    通过npm init 创建 package.json文件 参数: name:项目名字 version: 版本号 description: 项目介绍 main: 项目的入口文件 scripts: npm ...

  3. 连接池设置导致的“血案” 原创: 一页破书 一页破书 5月6日 这个问题被投诉的几个月了,一直没重视——内部客户嘛😿 问题现象: 隔几周就会出现 A服务调用B服务超时 脚趾头想就是防火墙的问题,A、B两服务之间有防火墙 找运维查看防火墙日志确实断掉了tcp连接,但是是因为B服务5分钟没有回包,下面这个表情就是我当时的心情——其实我们在防火墙、A服务、B服务都抓包了,几十个G的t

    连接池设置导致的“血案” 原创: 一页破书 一页破书 5月6日 这个问题被投诉的几个月了,一直没重视——内部客户嘛

  4. Maven中的SnapShot版本和Release版本

    # Maven中的SnapShot版本和Release版本 ## 区别 - SnapShot 快照版本- Release 发布版本 ## 重要区别 - 本地获取这些依赖的机制不同,如果是快照版本,Ma ...

  5. 安装TensorFlow时出现ERROR: Cannot uninstall 'wrapt'问题的解决方案

    pip install -U --ignore-installed wrapt enum34 simplejson netaddr pip install -i https://pypi.tuna.t ...

  6. React——嵌入已有项目 && jsx

    Add React to a Website React has been designed from the start for gradual adoption, and you can use ...

  7. Apache配置优化一(查看当前apache数据)

    1.查看当前的运行模块 httpd -l 2.查看httpd进程数 ps -ef | grep httpd | wc -l 3.查看请求80服务的client ip按照连接数排序 netstat -n ...

  8. 如何配置docker仓库

    创建文件 /etc/docker/daemon.json,写入国内镜像URL地址 { "registry-mirrors": [ "https://rq5uyt7.mir ...

  9. OAuth 2.0 授权认证详解

    一.认识 OAuth 2.0 1.1 OAuth 2.0 应用场景 OAuth 2.0 标准目前被广泛应用在第三方登录场景中,以下是虚拟出来的角色,阐述 OAuth2 能帮我们干什么,引用阮一峰这篇理 ...

  10. 【VS开发】TCP服务端如何判断客户端断开连接

    原文出自:http://www.cnblogs.com/youxin/p/4056041.html 一篇文章:   最近在做一个服务器端程序,C/S结构.功能方面比较简单就是client端与serve ...