← 返回信息流
AI 资讯Hacker News·6 天前

动手编写一个简单APL解释器(一)

原标题:Let's build a simple interpreter for APL – part 1

速览

本系列教程旨在教读者构建一个简单的APL语言解释器。第一部分从基础概念入手,逐步讲解实现思路。适合对编程语言实现感兴趣的开发者。

AI 深度解读

背景

本文是系列博客“Let's build a simple interpreter for APL”的第一部分,作者受 Ruslan Spivak 的经典系列“Let's build a simple interpreter”(基于 Pascal 的解释器构建教程)启发。作者此前曾基于该系列创建了 Roj 编程语言,现在决定再次研读该系列,但目标转向构建一个 APL 解释器。APL 是一种以数组为中心、符号丰富的编程语言,其执行顺序从右向左,与 Pascal 等主流语言差异显著。作者通过撰写本系列,旨在深入学习 APL、锻炼 Python 编程能力、记录实现过程,并帮助读者自行构建 APL 解释器。

核心内容

本博客的目标是解析简单的 APL 语句,支持以下特性:

  • 浮点数与整数(正数和负数,APL 中用 ¯ 表示负号,例如 ¯3 代表 -3)以及这些数值的向量;
  • 函数 +-×÷ 的一元(monadic)和二元(dyadic)用法;
  • 交换/切换运算符 (commute/switch operator);
  • 括号表达式。

词法分析(Tokenization)

第一步是将 APL 源代码拆分为 token(标记),去除不必要的空白字符,并识别每个字符的含义。例如,识别数字是整数还是浮点数,识别 APL 符号并关联其名称。

作者定义了 Token 类,包含以下 token 类型:INTEGERFLOATPLUSMINUSTIMESDIVIDENEGATECOMMUTELPARENSRPARENSEOF(文件结束符)。同时提供了从字符到 token 类型的映射(WYSIWYG,所见即所得),例如 + 映射为 PLUS- 映射为 MINUS× 映射为 TIMES÷ 映射为 DIVIDE( 映射为 LPARENS) 映射为 RPARENS 映射为 COMMUTE

Token 类实现了 __str____repr__ 方法,以便友好地打印 token 实例。

Tokenizer 类

Tokenizer 类负责将源代码字符串转换为 token 列表。关键设计决策:

  • 从右向左扫描:因为 APL 的执行顺序是从右向左,所以 tokenizer 从字符串末尾开始,逐步向左移动光标。
  • advance() 方法将光标左移一位,并更新 current_char,当光标到达字符串开头(即位置小于 0)时,将 current_char 设为 None
  • skip_whitespace() 跳过空格和制表符。
  • get_integer() 解析连续的数字字符,返回整数子串。
  • get_number_token() 解析数字 token:先获取整数部分,检查是否紧跟小数点(.),若有则继续获取小数部分;然后检查是否前有 ¯ 符号(表示负数),若有则添加负号。最终根据是否包含小数点返回 FLOATINTEGER token。
  • get_wysiwyg_token() 根据当前字符从映射中获取对应 token(如 +- 等)。
  • get_next_token() 调用 skip_whitespace() 后,根据当前字符类型(数字、WYSIWYG 字符、或空)返回相应 token,若无法识别则抛出异常。
  • tokenize() 方法不断调用 get_next_token() 直到遇到 EOF token,将所有 token 收集到列表中,最后反转(因为是从右向左收集,反转后顺序变为从左到右,但注意 EOF token 会出现在列表首位)。例如,表达式 5 -⍨ ¯2.3 会被 tokenize 为 [Token(EOF, None), Token(INTEGER, 5), Token(MINUS, -), Token(COMMUTE, ⍨), Token(FLOAT, -2.3)]

抽象语法树(AST)的规划

获得 token 列表后,需要构建抽象语法树(AST)以结构化表示程序。AST 的构建也是从右向左遍历 token 列表,识别标量、数组、运算符、一元/二元函数等。作者计划先定义 APL 子集的语法(grammar),然后基于语法生成 AST,从而简化后续的解释过程。本博客尚未给出完整的 AST 构建代码,但已为后续部分打下基础。

关键要点

  • APL 的执行顺序是从右向左,因此 tokenizer 选择从右向左扫描,这与其他大多数语言的解释器不同。
  • APL 负数使用 ¯ 符号,而非减号 -,处理时需注意符号的上下文(一元 vs 二元)。
  • Token 类型设计:包括 INTEGERFLOATPLUSMINUSTIMESDIVIDENEGATECOMMUTELPARENSRPARENSEOF,并定义了字符到类型的映射。
  • 数字解析:支持整数、浮点数
查看原文 →mathspp.com