到目前为止,我们的 REPL 更像是一个 RLPL,一个 read-lex-print-loop。 我们还不知道如何评估代码,所以用“evaluate”替换“lex”仍然是不可能的。 但我们现在最肯定知道的是解析。 是时候用“parse”替换“lex”并构建一个RPPL。
// repl/repl.go
func Start(in io.Reader, out io.Writer) {
scanner := bufio.NewScanner(in)
for {
fmt.Printf(PROMPT)
scanned := scanner.Scan()
if !scanned {
return
}
line := scanner.Text()
l := lexer.New(line)
p := parser.New(l)
program := p.ParseProgram()
if len(p.Errors()) != 0 {
printParserErrors(out, p.Errors())
continue
}
io.WriteString(out, program.String())
io.WriteString(out, "\n")
}
}
func printParserErrors(out io.Writer, errors []string) {
for _, msg := range errors {
io.WriteString(out, "\t"+msg+"\n")
}
}
在这里,我们扩展循环以解析我们刚刚在 REPL 中输入的行。 然后通过调用其 String 方法打印解析器的输出 *ast.Program,该方法递归调用属于该程序的所有语句的 String 方法。 现在我们可以使用解析器进行旋转 - 在命令行上交互:
$ go run main.go
Hello mrnugget! This is the Monkey programming language!
Feel free to type in commands
>> let x = 1 * 2 * 3 * 4 * 5
let x = ((((1 * 2) * 3) * 4) * 5);
>> x * y / 2 + 3 * 8 - 123
((((x * y) / 2) + (3 * 8)) - 123)
>> true == false
(true == false)
>>
很好! 现在,我们可以使用任何基于字符串的 AST 表示来输出,而不是调用 String。 我们可以添加一个 PrettyPrint 方法来打印 AST 节点的类型并正确地指定其子节点,或者我们可以使用 ASCII 颜色代码,或者我们可以打印 ASCII 图形,或者……重点是:天空是极限。 但是我们的 RPPL 仍然有一个巨大的缺点。
这是解析器遇到错误:
$ go run main.go
Hello mrnugget! This is the Monkey programming language!
Feel free to type in commands
>> let x 12 * 3;
expected next token to be =, got INT instead
>>
这不是一个很好的错误信息。 我的意思是,它可以完成工作,是的,但它不是很好,是吗? 这Monkey 编程语言值得更好的。 这是一个更用户友好的 printParseError增强用户体验的功能:
// repl/repl.go
const MONKEY_FACE = ` __,__
.--. .-" "-. .--.
/ .. \/ .-. .-. \/ .. \
| | '| / Y \ |' | |
| \ \ \ 0 | 0 / / / |
\ '- ,\.-"""""""-./, -' /
''-' /_ ^ ^ _\ '-''
| \._ _./ |
\ \ '~' / /
'._ '-=-' _.'
'-----'
`
func printParserErrors(out io.Writer, errors []string) {
io.WriteString(out, MONKEY_FACE)
io.WriteString(out, "Woops! We ran into some monkey business here!\n")
io.WriteString(out, " parser errors:\n")
for _, msg := range errors {
io.WriteString(out, "\t"+msg+"\n")
}
}
这样更好! 如果我们现在遇到任何解析器错误,我们就会看到一只猴子,这真的超出了任何人的要求:
$ go run main.go
Hello mrnugget! This is the Monkey programming language!
Feel free to type in commands
>> let x 12 * 3
__,__
.--. .-" "-. .--.
/ .. \/ .-. .-. \/ .. \
| | '| / Y \ |' | |
| \ \ \ 0 | 0 / / / |
\ '- ,\.-"""""""-./, -' /
''-' /_ ^ ^ _\ '-''
| \._ _./ |
\ \ '~' / /
'._ '-=-' _.'
'-----'
Woops! We ran into some monkey business here!
parser errors:
expected next token to be =, got INT instead
>>
转念一想……无论如何,是时候开始评估我们的 AST 了。
< 2.8扩展解析器 | > 3.1赋予符号意义 |
---|