记录一下如何实现一门编程语言~(1)

841 阅读3分钟

这是一个非常长期而又伟大的目标

至少, 在计算机的领域, 自己动手实现一个工具是一个很好的学习的过程

所以在简单了解了一下基础之后, 就决定要开工了!

先实现 目标语言 -> js 这样一个简单的小目标再说

PS: 主要是为了记录一些遇到的问题和思考的问题

先使用最简单的方式实现 print

至少很多方面, 很可能就先基于 js 进行实现了

./main.sx

可以先使用 js 来实现一些很麻烦的功能, 反正不行就调用 js 的一个函数嘛, 就像这样

./io.js

嘛...看起来好像是一个很简单的的过程, 也就这么两行代码不是吗? 但实际上, 可能大概, 稍微有一丢丢的复杂

虽然只需要解析两行代码, 但还是需要对这两行代码进行一些分组分类操作的

比如有一些文本是关键字: [import, as] (反正个人感觉 js 的 import 有点奇怪, 所以稍稍修改了一下下

然后有一些是字面量: ['./io.js', 123] (其实有考虑这里要不要把引号作为标示符去解析, 为了简单还是先作为整体吧

最后还有一些变量名字?: [io, print] (姑且先这么称呼吧

一些操作符: [.] 和 括号 [(, )] (感觉并不是很懂, 但直觉上最好把括号单独作为一个分类拎出来 orz, PS: 可能是由于括号都是成对出现的大概

好啦, 这样基本上就把最基本的元素准备齐全了, 大概这样

之后需要做的就是把它从字符串解析一下下~

好~ 现在有了一个很烂的匹配算法, 不要在意一些细节~

至少现在已经可以将代码从文本转换成结构化的数据了~

之后想办法处理一下这个结构

虽然这次很短, 但是未完待续~

PS: 补一下相关的工具函数 orz

以及这个文件现在的源代码, 稍微改动了一丢丢 (number -> integer


const tokenTypes = [
    'keyword',
    'name',
    'operator',
    'paren',

    // 字面量类型
    // PS: 想了一下, 字面量还是归类为 tokens 可能会好一些?
    'string',
    'integer',
]

const keywords = [
    'import',
    'as',
]

const parens = ['(', ')']

const operator = ['.']

function getTokens(input) {  
    const tokens = []
    let cur = 0
    function whileForChar(char) {
        const ending = char
        let str = char
        while(str === ending || 
            char !== ending && cur < input.length
        ) {
            cur++
            char = input[cur]
            str += char
        }
        cur++
        return str
    }

    function whileForRegexp(regexp) {
        let str = ''
        char = input[cur]
        while (char.match(regexp) && cur < input.length) {
            str += char
            cur++
            char = input[cur]
        }
        return str
    }
    
    while(cur < input.length) {
        let char = input[cur]

        // 空格或者换行, 就暂且先认为是一个 str
        if (char.match(/\s/)) {
            if (char === '\n') {
                tokens.push({ type: 'operator', value: '\n' })
            }
            cur++
            continue
        }

        // 匹配括号~
        if (parens.includes(char)) {
            tokens.push({ type: 'paren', value: char })
            cur++
            continue
        }

        // 匹配操作符~
        // PS: 考虑到操作符不止会有一个, 突然想起来还有上面的括号!
        if (operator.includes(char)) {
            // 先这样实现吧~ 
            tokens.push({ type: 'operator', value: char })
            cur++
            continue
        }

         // 匹配字符串, 写的有点烂
         if (char.match(/\'|\"/)) {
            const str = whileForChar(char)
            tokens.push({ type: 'string', value: str })
            continue
        }

        // 匹配数字
        if (char.match(/\d/)) {
            const str = whileForRegexp(/\d/)
            tokens.push({ type: 'integer', value: str })
            continue
        }

        // 匹配一部分变量名
        if (char.match(/[A-Z]|_/)) {
            const str = whileForRegexp(/[a-zA-Z]|_|[0-9]/)
            tokens.push({ type: 'name', value: str })
            continue
        }

        // 匹配关键字
        if (char.match(/[a-z]/)) {
            const str = whileForRegexp(/[a-zA-Z]|_|[0-9]/)
            if (!keywords.includes(str)) {
                tokens.push({ type: 'name', value: str })
                continue
            }
            tokens.push({ type: 'keyword', value: str })
            continue
        }
        console.error('not match')
        cur++
    }
    return tokens
}

module.exports = { getTokens }