把文法存成数据

文法也可以当数据存:每条产生式是「左边 → 右边的候选列表」。看 stmt 有几个候选、第一个候选是什么: G = { "stmt": [["let", "IDENT",

开始练习 →

补全:看开头选规则

(每道题开头都有同一段:T() 是上一站 lexer 的替身——源码里 token 之间用空格分开,它切成 (kind, text, line, col);show() 把树写成一行:二元运算全加括号,语句之间用 |。) 补全 which(

开始练习 →

补全:数一数 sum 里有几个 term

(每道题开头都有同一段:T() 是上一站 lexer 的替身——源码里 token 之间用空格分开,它切成 (kind, text, line, col);show() 把树写成一行:二元运算全加括号,语句之间用 |。) sum := te

开始练习 →

递归下降的核心做法

「递归下降」写 parser 的核心做法是【0】。

开始练习 →

peek 和 advance

parser 里两个最基本的动作:peek() 和 advance()。它们的区别是【0】。

开始练习 →

expect 干什么

expect(";") 的意思是【0】。

开始练习 →

为什么叫「递归」

块里套块,一层层走进去 走到最里层,还记得从哪儿出来吗 玩具语言的文法(八节共用):program := stmt*;stmt := "let" IDENT "=" expr ";"

开始练习 →

最小的 parser 走一句

(每道题开头都有同一段:T() 是上一站 lexer 的替身——源码里 token 之间用空格分开,它切成 (kind, text, line, col);show() 把树写成一行:二元运算全加括号,语句之间用 |。) 一个只认「let

开始练习 →

补全:写出 let 语句的函数

(每道题开头都有同一段:T() 是上一站 lexer 的替身——源码里 token 之间用空格分开,它切成 (kind, text, line, col);show() 把树写成一行:二元运算全加括号,语句之间用 |。) 补全 let_st

开始练习 →

补全:看开头分两路

(每道题开头都有同一段:T() 是上一站 lexer 的替身——源码里 token 之间用空格分开,它切成 (kind, text, line, col);show() 把树写成一行:二元运算全加括号,语句之间用 |。) 补全 stmt:开

开始练习 →