登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go教程

Go scanner.Scanner.ErrorCount 怎么统计源码词法错误

来源:17golang原创

时间:2026-10-04 20:17:13 355浏览 收藏

用 go/scanner 做源码词法扫描时,统计错误的关键不是数 token.ILLEGAL,而是让 Scanner 完整扫描到 token.EOF,再读取 s.ErrorCount。如果还需要展示行列和原因,就在 Init 时传入 scanner.ErrorHandler,把它作为明细通道。

官方地址:https://pkg.go.dev/go/scanner

要点速览
  • ErrorCount 统计扫描期间遇到的错误,初始化和每次扫描都可能触发错误处理。
  • Scan 为了尽量继续工作,可能在发生错误后仍返回看起来合法的 token。
  • 计数负责判定是否通过,ErrorHandler 负责保存位置和消息,两者不要混为一个指标。

先把错误计数绑定到一次完整扫描

Scanner.Init 会重新初始化扫描器,并把 ErrorCount 清零。源字节长度必须与 token.File 的大小一致,否则初始化会 panic。下面的写法把错误明细放进切片,最终用计数做机器判断:

package main

import (
    "fmt"
    "go/scanner"
    "go/token"
)

func main() {
    // 故意放入非法字符和未闭合注释,演示错误计数与明细收集。
    src := []byte("package demo\nfunc main() { @ }\n/*")
    fset := token.NewFileSet()
    file := fset.AddFile("demo.go", fset.Base(), len(src))

    var s scanner.Scanner
    var details []string
    s.Init(file, src, func(pos token.Position, msg string) {
        // handler 只保存诊断信息,不负责替代 ErrorCount。
        details = append(details, fmt.Sprintf("%s: %s", pos, msg))
    }, 0)

    for {
        // 必须持续取 token,直到 EOF,错误才会被完整发现。
        _, tok, _ := s.Scan()
        if tok == token.EOF {
            break
        }
    }

    fmt.Printf("errors=%d, details=%d\n", s.ErrorCount, len(details))
    for _, detail := range details {
        fmt.Println(detail)
    }
}

这里的 errors 应在扫描结束后读取。不要在第一次 Scan 后就判断,因为后续 token 仍可能触发错误;也不要把 details 的长度当成通用计数契约,业务若修改了 handler(例如过滤或合并消息),它就不再等于原始错误数。

为什么不能只数 token.ILLEGAL

Go scanner 从源字节、初始化到 Scan 与 ErrorCount 的关系说明图
图1:Go scanner 输入、错误回调与 ErrorCount 的静态结构说明图,不是运行截图。

Scan 返回 token.ILLEGAL 时,字面量通常是触发问题的字符,但词法错误不只表现为这个 token。未闭合的块注释、格式不完整的字面量等情况,也可能先通过错误处理器报告,再尽量返回可继续处理的 token。因此,正确的通过条件应是 s.ErrorCount == 0,而不是“没有看到 ILLEGAL”。

这也是 ErrorHandler 的价值:它接收 token.Position 和消息,适合输出文件名、行号、列号;ErrorCount 则是稳定的汇总值,适合让批处理任务返回失败状态。两条通道同时保留,既能定位问题,也不会依赖 token 恢复策略。

把统计口径和复用边界说清楚

ErrorCount、ErrorHandler 和 ILLEGAL token 边界关系说明图
图2:ErrorCount、ErrorHandler 与 ILLEGAL token 的职责边界说明图,不是运行截图。

有三个边界容易在工具代码里被忽略:

  • 只统计一次:在同一个 Scanner 上重复调用 Scan 不会重新产生一轮结果;需要重新扫描时再次调用 Init,它会清零计数。
  • 错误去重另算:如果按每行只保留一条错误,应使用自己的集合或 scanner.ErrorList.RemoveMultiples;这改变的是展示列表,不是扫描器本身的 ErrorCount。
  • 注释不是错误统计开关:需要把注释作为 token 取出时启用 scanner.ScanComments,它只改变注释处理方式,不会把已有词法错误变成普通 token。

最终可以把结果封装成两个字段:Count 用于门禁,Diagnostics 用于反馈。调用方只关心是否通过时读取计数;编辑器或命令行需要高亮时再消费明细。

常见误区与判断方法

问:ErrorHandler 没有传入,能不能统计?
可以。传入 nil 时不会收到明细回调,但 ErrorCount 仍会递增。

问:扫描结果里没有 ILLEGAL,是否就代表源码没有词法错误?
不代表。扫描器会尽量恢复并继续返回 token,最终仍应检查 ErrorCount。

问:什么时候读取计数最稳妥?
完成循环并收到 token.EOF 后读取;若初始化阶段就触发错误,计数也会包含在这次扫描结果里。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>