自制简易解释器

本文介绍了作者使用C语言自制的一个简易动态语言解释器,其语法设计受到Python和Go语言的影响。解释器实现了数据类型、控制语句、循环、函数等基本功能,使用lex和yacc进行词法和语法分析。文章详细讲解了表达式分析树的构建、解释器的运行环境和解释过程,并分享了作者在实现过程中的学习心得。
摘要由CSDN通过智能技术生成

title: 自制简易解释器
date: 2019-02-18 22:00:01
tags: interpreter
categories: compilation
blog: https://withas.me


自制简易解释器

用C语言写了一个简单的动态语言解释器, 代码放在了github上面:hedegehog. 编译, 运行可以看看github上的readme.

先简单介绍下这门语言. hedgehog 的多数设计和 python 比较相似, 无需声明变量类型, if,for等语句没有块级作用域. 语法上又有点像 go 语言: if, for不需要(), 但是后面的代码块都必须加{}; 没有while, 不过有for condition {}来替代. 不过行尾必须加;这点和 go 不同. 大多数设计都是为了简化实现方式, 比如必须加{}, ;是为了简化语法的解析.

已实现的功能

  • 数据类型

    a = 10;//int
    b = 3.14;//float
    c = true;//boolean
    d = null;//null
    s = "Hello, World!";//string
    
  • 控制语句

      a = 10;
      if a > 10 { // `()` is not necessary.
          b = a+20;
      } elsif a==10 {
          b = a+10;
      } else {
          b = a-10;
      }
      print(b);
      // block has no local environment, 
      // so 'b' is a global variable.
    
  • 循环

      for i=0; i<10; i=i+1 {
          print(i);
          if i>=4 {break;}
      }
      i = 0;
      for i<10 {
          if i<5 {continue;}
          print(i);
      }
    
  • 函数
    function也被看作一种值(基本数据类型), 不过目前还没有对它实现垃圾回收, 所以直接以函数赋值或者其他操作会出现内存错误.

      // 模仿python首页的函数:)
      func fbi(n) {
          a, b = 0, 1;
          for a<n {
              print(a);
              a, b = b, a+b;//支持这种赋值方式
          }
      }
      fbi(100);
    
      func factorial(n) {
          if n==0 {return 1;}
          return n*factorial(n-1);
      }
      print(factorial(5));
    

    目前只实现了一个原生函数print. print接收一个基本数据类型作为参数, 输出并换行, 或者无参数, 直接换行.

  • 运算符
    大多数与c保持一致, 除了&, |. 因为没有提供位运算的功能, 所以直接用这两个符号表示逻辑与和逻辑或.

    b = 2;
    a = 10;
    if a>20 & b<10 {
        print("`b` is less than 10 and `a` is greater than 20");
    }
    if a>20 | b<10 {
        print("`b` is less than 10 or `a` is greater than 20");
    }
    

概述

首先词法分析和语法分析, 构建分析树. 这里以a=1+2*3+fn();为例, 介绍一下表达式分析树的构建.

首先, 它是一个赋值表达式, 把右边的值1+2*3+fn()赋给左边的变量a. 而1+2*3+fn() 又由加法表达式, 乘法表达式, 函数调用表达式构成. yacc中编写的规则会约束表达式构建的顺序, 构建过程大概是这样的:

a = 1 + 2 * 3 + fn()
identifier = value + value * value + function_call // 词法分析
identifier = value + value * value + value // function_call 约归为value
identifier = value + multiply_expression + value // 根据规则, 先生成乘法表达式
identifier = add_expression + value // 把前两项归约为加法表达式
identifier = add_expression // 继续归约(加法运算遵循从左到右)
identifier = expression // 归约为更一般的普通表达式
assgin_expression // 匹配到赋值表达式的规则, 归约为赋值表达式
expression // 赋值表达式归约为一般表达式

然后就可以构建了下面的分析树了:

求值的时候从最底层依次往上求值, 就能得到表达式的值.

语法与词法分析

这部分直接使用lex做词法分析, yacc做语法分析. 这两个工具在大多数UNIX上都有预装, GUN提供的版本分别叫bison, flex. 直接用bison生成的文件可能和yacc有些区别(需要修改生成文件的的文件名, 或者改c语言文件中包含的头文件名), 不过在Linux下安装了bison可以直接使用yacc命令. flex 与 lex 生成文件没有区别.

yacc与lex网上有大量的资料, 而且使用比较简单, 这里就仅作简单的介绍.

lex可以使用正则表达式做匹配:

"func" return FUNCTION;//func 函数定义关键字
[A-Za-z_][A-Za-z0-9_]* {
	//辨识符匹配
    yylval.identifier = in
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值