写一个整数四则运算的解析器——词法分析部分

写一个简单的词法、语法分析器,来最终分析出整数四则运算表达式的结果。

为了简化词语法分析我们只允许出现0~9,+,-,*,/,空格, , 这几个字符

词法分析:

方法1. 状态机

我们先准备3个判断方法:

// 是否是数字
function isNum(letter) {
    return letter === '0' || letter === '1' || letter === '2' || letter === '3' || letter === '4' || letter === '5' || letter === '0' || letter === '6' || letter === '7' || letter === '8' || letter === '9'
}
// 是否是运算符
function isOperater(letter) {
    return letter === '+' || letter === '-' || letter === '*' || letter === '/'
}
// 是否是间隔符
function isEmptyLetter(letter) {
    return letter === ' ' || letter === '
' || letter === '
'
}

定义生成token的函数:

const tokenList = []
function generateToken(type, token) {
    console.log("生成token: " + token);
    tokenList.push({type, token});
}

定义状态转移函数:

let token = []
function startToken(letter) {
    if (isNum(letter)) {
        // 如果是数字,则进入inNumber状态
        token.push(letter)
        return inNumber
    } else if (isOperater(letter)) {
        // 如果是+-*/, 就马上生成一个token
        generateToken(letter, letter)
        return startToken
    } else if (isEmptyLetter(letter)) {
        // 如果是空白字符,则跳过
        return startToken
    } else {
        // 如果是其他字符则报错
        throw new Error('出现意外字符')
    }
}

function inNumber(letter) {
    if (isNum(letter)) {
        token.push(letter)
        return inNumber
    } else {
        // 直到遇到非数字, 把前面push的数字生成一个数字token, 然后清空token
        generateToken('number', token.join(''))
        token = []
        // 最后让新的letter马上执行一次startToken
        return startToken(letter)
    }
}

开始词法分析:

// 要词法分析的字符串
const str = '123* 656 - 644 + 3131'
// 分割成一个个字母
let strArr = str.split('');
// 定义状态机
let state = startToken
// 遍历字母,不停地更新状态机
for(let letter of strArr) {
    state = state(letter)
}
// 结束
state(Symbol('EOF'))
generateToken('EOF', 'EOF')

 得出结果:

方法2. 正则分析

// 要词法分析的字符串
let str = '123* 656 - 644 + 3131'
// 过滤间隔符
str = str.replace(/[
 ]/g, '')

const operatorRegExp = /[+-*/]/g
// 获取运算的数字token
let numList = str.split(operatorRegExp)
// 获取运算符token
let operatorList = str.match(operatorRegExp)

const tokenList = []
numList.forEach((item, idx) => {
    tokenList.push({type: 'number', token: item})
    if (idx !== numList.length - 1) {
        tokenList.push({type: operatorList[idx], token: operatorList[idx]})
    }
})
// 结束
tokenList.push({type: 'EOF', token: 'EOF'})
console.log(tokenList)

得出结果:

到这里词法分析就已经完成了。

原文地址:https://www.cnblogs.com/amiezhang/p/11061605.html