代码地址

# HelloWorld.ice
print("hello, world")

前言(废话)

其实从开始学习编译原理到现在已经有快半年的时间了,但是其间常常不能坚持看下去龙书(经常三天打鱼两天晒网,更何况每次打鱼不到半小时就累得不行又会放下书(笑)),截至到现在只勉强看完了前六章的部分,半年间其它事也没有做,其实想想上大学已经快两年了还是一事无成,知识也没有学到,不免觉得很羞愧。

暑假也要到了,这个学期马上也要结束了,临近大二结束之际,还是尝试着写一下以前想写的玩具吧,而本系列就是对这段过程的记录,也算是对龙书前六部分的一个小实践&总结(后面的部分可能看完了我也写不出什么东西来)。

其实再写这个解释器之前,我是拿lex + yacc + llvm照着tutorial试着拼过一个编译器,但是llvm对我来说可能有些太难了(苦笑)。残破不堪的代码在lyli分支上。

这个系列的教程(如果可以算作教程的话),其实主要还是实现了前端部分(一样有很多bug),而parser早就被研究透了,所以本教程基本上没有什么价值,可能唯一具有优势的地方就是我跟愿意看这几篇文章的读者大概是相同的入门(或者还未入门)的水平。

本教程分为四章

  1. 明确目标 & 设计语言
  2. 实现词法分析器
  3. 实现语法分析器
  4. 实现基础数据类型

且希望能达到在读者阅读完本系列后,能完成一个支持以下几项的解释器语言

  1. 整型、浮点型以及字符串类型
  2. 常见双目运算符
  3. 变量定义
  4. 函数定义及调用
  5. 基本控制流语句
  6. lambda表达式

适合读者

  1. 对编译原理感兴趣,但是还尚未正式的开始学习
  2. 尝试完成一个玩具解释器但不知道如何下手

正文

在正式手撸之前,我们要先确立我们要撸的是个什么玩意儿(你这不是废话吗摔)。毕竟在后期想要增加一些新的骚操作(新特性)的时候,若没有在一开始进行设计,难免会出现各种重构上令人烦躁的问题(虽然如果你按照本教程撸出来的解释器必然会带来重构上各种糟糕的问题,但是重构本身就是一件会带来各种糟糕的问题的事情(所以就不要介意了)),但是在正式写代码之前进行设计,总是一件应该做的事。

解释什么

从解释器角度来说,我们解释的是字符串,在验证字符串满足规则后进行解释,在解释完之后将其按照语义正确执行,而这个规则就是我们Ice的语法规则。

从词法分析器的角度来说,我们解释是字符串,只需要输入的字符串满足我们为词素指定的规则,然后根据输入的字符串返回token给语法分析器就可以了。

从语法分析的角度来说,我们解释的是token序列,且通过预测分析法依据token序列选择正确的产生式并返回抽象语法树(Abstract Syntax Tree)。

输入形式

只考虑交互式输入(即一行一行的输入)

如何解释

本项目中主要包含以下几个类:

  • Token:实例化的Token对象包含一个词素的类型以及词素值
  • LexicalAnalyzer:解析输入字符串,返回token序列
  • Node:实例化的Node及其派生类对象包含AST中一个节点所应具有的信息
  • SyntaxAnalyzer:根据token序列预测分析,返回AST(实质是一个Node或其派生类实例)
  • IceObject:包括自身类型信息,以及实现相关运算
  • Env:符号表,存储Ice运行时的对象信息
  • Interpreter:只提供run()接口供main函数调用,隐藏内部逻辑

好了,基本上结构就是这样,下面可以着手考虑Ice具备怎么样的语法了。

Ice 语法

整形、浮点型以及字符串类型
1
1.0
"hello, world"
常见双目运算符
1 + 1
(100 + 20) * 6 / 3
10 = 10
5 <= 3
变量定义
@a: 1
函数定义及调用
@add(a, b): a + b

@mul(a, b)
{
return a * b
} mul(mul(2, 3), add(2, 3))
基本控制流语句
@fib(n)
{
if (n = 0) + (n = 1)
{
return 1
}
else
{
return fib(n-1) + fib(n-2)
}
} fib(10) # 89 @a: 3
while a
{
print(a)
@a: a - 1
} @a: 0
do {
@a: a + 1
if a = 3
{
break
}
print(a)
} while a < 5 for 1 to 5
{
@a: a + 1
if a = 3
{
continue
}
print(a)
}
lambda表达式
@add(a, b): a + b
@mul: @(a, b){
return a * b
}
@(a, b){ return a / b }(9, 3) @quadraticSum: @(a, b){
@sqrt: @(n){ return n * n }
return @(a, b){ return a + b }(sqrt(a), sqrt(b))
}

基本上就是这样,那么如果你还继续打算看的话,下一章将会开始手撸Ice的词法分析器。

以鶸ice为例,手撸一个解释器(一)明确目标的更多相关文章

  1. 五分钟,手撸一个Spring容器!

    大家好,我是老三,Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开S ...

  2. 使用Java Socket手撸一个http服务器

    原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomc ...

  3. 【手撸一个ORM】MyOrm的使用说明

    [手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...

  4. 第二篇-用Flutter手撸一个抖音国内版,看看有多炫

    前言 继上一篇使用Flutter开发的抖音国际版 后再次撸一个国内版抖音,大部分功能已完成,主要是Flutter开发APP速度很爽,  先看下图 项目主要结构介绍 这次主要的改动在api.dart 及 ...

  5. 通过 Netty、ZooKeeper 手撸一个 RPC 服务

    说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...

  6. C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

    C#基于Mongo的官方驱动手撸一个简易版MongoDB-ORM框架 如题,在GitHub上找了一圈想找一个MongoDB的的ORM框架,未偿所愿,就去翻了翻官网(https://docs.mongo ...

  7. 手撸一个SpringBoot-Starter

    1. 简介 通过了解SpringBoot的原理后,我们可以手撸一个spring-boot-starter来加深理解. 1.1 什么是starter spring官网解释 starters是一组方便的依 ...

  8. 手撸一个springsecurity,了解一下security原理

    手撸一个springsecurity,了解一下security原理 转载自:www.javaman.cn 手撸一个springsecurity,了解一下security原理 今天手撸一个简易版本的sp ...

  9. Golang:手撸一个支持六种级别的日志库

    Golang标准日志库提供的日志输出方法有Print.Fatal.Panic等,没有常见的Debug.Info.Error等日志级别,用起来不太顺手.这篇文章就来手撸一个自己的日志库,可以记录不同级别 ...

随机推荐

  1. Tomcat8/9的catalina.out中文乱码问题解决

    OS: Red Hat Enterprise Linux Server release 7.8 (Maipo) Tomcat: 9 中文显示为???问号 在$CATALINA_HOME/conf下的l ...

  2. 通过springBoot集成搭建webScoket服务器

    前言: 最近工作中有一个需求,就是服务端要主动推送消息给客户端,而我们平常的Http请求只能一请求一响应,为此学习了webScokset通讯技术,以下介绍的是java 通过SpringBoot集成we ...

  3. 【Java】包装类

    文章目录 包装类 什么是包装类 基本数据类型-->包装类 包装类-->基本数据类型 自动装箱与自动拆箱 基本数据类型.包装类与String的转换 基础数据类型.包装类-->Strin ...

  4. css中两种居中方式text-align:center和margin:0 auto 的使用场景

    关于使用text-align:center和margin:0 auto 两种居中方式的比较 前言:最近由于要学习后端,需要提前学习一部分前端知识,补了补css知识,发现狂神在讲这一部分讲的不是特别清楚 ...

  5. [C# 学习]窗体间调用控件

    一.方法1: 假如有两个窗体,Form_A和Form_B,每个窗体里都有一个按键,Button_A和Button_B,要实现单击Button_A显示窗体B,那么窗体A中Buttom_A的单击事件的程序 ...

  6. Kindle连接移动的 Wi-Fi 时要求进行网页浏览器登陆怎么办?

    在电脑上新建一个新文件,名为"WIFI_NO_NET_PROBE",同时把后缀名删掉,让它变成一个无格式文件.Kindle 连接电脑,把新建的文件放进Kindle的根目录,断开Ki ...

  7. maven一键构造及常用命令

    maven一键构造及常用命令 1.maven的一键构建 我们不再使用本地的Tomcat对项目进行编译.测试.运行.打包.安装.部署等一系列过程,而是使用maven自身集成的Tomcat插件来完成这些操 ...

  8. Visualizing and Understanding Convolutional Networks论文复现笔记

    目录 Visualizing and Understanding Convolutional Networks 论文复现笔记 Abstract Introduction Approach Visual ...

  9. k8s基本概念,资源对象

    kubernetes里的master指的是集群控制节点 master负责是整个集群的管理和控制 kubernetes3大进程 API server 增删改查操作的关键入口 controller man ...

  10. 常见线程池 newFixedThreadPool 的简单使用

    package com.aaa.threaddemo; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurr ...