【完结】在 CovScript 3 基础上从头打造一门中文编程语言

是的,对于生成器来说很难猜测语法设计者的意图


搞定了cSYM的生成


有了 cSYM 就能准确报错了,虽然现在还没办法 Hack 到解释器里把报错翻译了,但至少能报错到正确的位置

1 个赞

endline为例,这里展示一下如何生成cSYM

    function visit_endline(nodes)
        var idx = 0
        # Condition
        block
            var matched = false
            if !matched && (typeid nodes[idx] == typeid parsergen.token_type && nodes[idx].type == "endl")
                matched = true
                # Visit endl token
                ++idx; target.println(""); csym_map.push_back(nodes[idx - 1].pos[1] - 1)
            end
            if !matched && (typeid nodes[idx] == typeid parsergen.token_type && nodes[idx].data == ";")
                matched = true
                # Visit term ";"
                ++idx; target.println(""); csym_map.push_back(nodes[idx - 1].pos[1])
            end
            if !matched
            	# Error
            	return
            end
        end
    end

这里 csym_map 是一个数组,我们只需要在每次打印换行的时候同步在数组里添加一个对应的行号就可以了。ParserGen 会自动给所有的词元插入位置信息,所以我们只需要定位到最近的词元并通过 pos 成员拿到所在的行号

这里有一个小 Tricky,对于换行符来说,应该把行号减一,否则就对应到下一行去了

然后就可以生成最终的 cSYM 文件了

var ofs = iostream.ofstream("./a.csym")
var dbg_info = "#$cSYM/1.0(" + gen.file_name + "):"
foreach it in gen.csym_map do dbg_info += to_string(it) + ","
dbg_info.cut(1)
ofs.println(dbg_info)
foreach line in gen.code_buff do ofs.println(line)

首先就是生成 cSYM 头,直接拼接字符串就可以了
然后因为 ParserGen 会保存文件缓存,所以直接将 gen.code_buff 输出到文件里即可
这样我们就得到一个 .csym 文件,可以通过 read_csym.csc 来验证

read_csym.csc 的参数是不带后缀的文件名。一般我们在生成的时候,如 a.cpl,会分别生成 a.csca.csym,也就是说文件名相同而后缀名不同。这种情况下当运行命令:

cs misc/read_csym.csc a

程序会分别读取 a.csca.csym

最后,加了一下小功能,目前可以做到:

ecs cpl.ecs run 源文件

ecs cpl.ecs debug 源文件

会分别调用解释器和调试器
虽然目前解释器和调试器的报错和交互还是英文的,但我们也有办法翻译
后面我会想办法增加本地化的功能

可以看到,Cov3 本身作为一门图灵完全、自举的通用型动态语言,去支持一门中文编程语言可以说是绰绰有余。就算需要更复杂的语义,在 AST Visitor 的基础上增加类型检查之类的也非常简单,或者遍历生成 CFG 实现代码分析、补全等
未来我还会进一步完善以 CovScript 为核心的语言生态,不仅服务于 Cov 自身,也服务于更多热爱 PL 的朋友们
本帖暂时完结

1 个赞

统计了一下,算上生成的代码,一共也就1000行,简单的很