只是替换一下解释器其实并不是很想水一篇
首先, 修正一下之前简易解释器的 traverse = =
估计也只有这些类型了, 缺了再补 orz
一个小工具函数~
然后稍微调整一下 visitor 的用到的参数
哦耶, 从结果上看大功告成!
由于没有输出所以声明的参数都没有被使用到~
对, 这就是不想单独为解释水一篇对原因
所以增加一个结果输出很困难吗
其实, 这并不应该是一件很困难的事情
但是, 解释 AST 时的幸福程度完全取决于之前设计 AST 时的健康状况, 至少我这一颗 AST 的健康状况不太乐观 = =
经过激烈而且不懈努力的强效, 这颗小树苗终于有了一丝丝微微要活过来的迹象, 不过看样子以及撑不了太久了
嘛...至少现在还能用 (手动斜眼
然后修改一下 visitor 的 CallExpression 的部分, 其实也只有这里有变动, 需要分别处理字面量和变量两种情况
调用函数也稍微有那么一丢丢的修改, 英文中间多了一个 simpleAST 的步骤 orz
好的~ 接下来就是输出四个变量~
完美撒花~
诶, 好像看起来也没有增加多少东西, 就要这么结束了吗
(话说为什么 print 不能放在同一行输出 4 个变量呢 (喂难道你忘记了之前就没有处理过 "," 这个 token 吗, 没处理过的东西要怎么解释呀啊喂 orz
嗯, 没错, 这次就是这么短, 再次撒花~
PS: 稍微总结一下, 至少目前来看, 这种程度的 “编程语言” 还属于 “业务” 的范畴, 就是等于说我接到了一个要处理文本和字符串的需求这样, 短期看基本也是这样一个节奏, 以处理字符串的思路继续构造这样一个 “编程语言”, 目前来看并没有太多需要参考编译相关书籍的必要
PS2: 毕竟以学习为目的, 在遇到问题之后再去找资料或者一边写一边找会好一些, 将书籍当作一个解决问题的工具, 而不是学习的工具, 至少...没有遇到难以解决的问题的时候, 可以先不考虑翻书 (纯个人看法, 不过早晚都会翻书的 = =
附上源码.jpg
traverser.js
const fs = require('fs')
const path = require('path')
function executeAST(ast, execPath) {
const vars = {}
const types = {}
traverser(ast, {
ImportDeclaration(node, parent) {
const p = path.resolve(execPath, node.source.value)
const js = fs.readFileSync(p, { encoding: 'utf-8' })
// 使用 js 的语法特性, 在内存中申请变量空间
vars[node.property.value] = eval(js)
},
CallExpression(node, parent) {
const key = parent.object.value.value
const obj = vars[key]
function printValue(val, type) {
// 浮点数特殊转换一下再输出 = =
return type !== 'float' ? val : val.toFixed(1)
}
const params = node.arguments.map(arg => {
const type = types[arg.value].value
if (arg.type === 'Identifier') {
return printValue(vars[arg.value], type)
}
if (arg.type.endsWith('Literal')) {
return printValue(arg.value, type)
}
})
// 链式调用的问题早晚要解决 = =
obj[node.property.value](...params)
},
VariableDeclaration(node, parent) {
vars[node.property.value] = node.value.value
types[node.property.value] = node.datatype
},
IntegerLiteral(node, parent) {
node.value = parseInt(node.value)
},
FloatLiteral(node, parent) {
node.value = parseFloat(node.value)
},
BooleanLiteral(node, parent) {
node.value = node.value === 'true' ? true : false
},
})
}
function traverser(ast, visitor) {
function traverseArray(array, parent) {
array.forEach(child => {
traverseNode(child, parent)
})
}
function traverseNodePropertys(node, props) {
props.forEach(p => {
traverseNode(node[p], node)
})
}
function traverseNode(node, parent) {
if (!node) {
return
}
const method = visitor[node.type]
// 有预感这个 switch 会很庞大
switch (node.type) {
case 'Program':
traverseArray(node.body, node)
break
case 'ImportDeclaration':
traverseNodePropertys(node, ['source', 'property'])
break
case 'VariableDeclaration':
traverseNodePropertys(node, ['property', 'value', 'datatype'])
break
case 'ExpressionStatement':
traverseNodePropertys(node, ['object', 'callee'])
break
case 'MemberExpression':
traverseNodePropertys(node, ['value'])
break
case 'CallExpression':
traverseArray(node.arguments, node)
traverseNodePropertys(node, ['property'])
break
case 'Identifier':
case 'StringLiteral':
case 'IntegerLiteral':
case 'FloatLiteral':
case 'BooleanLiteral':
traverseNode(node.value, node)
break
}
// 嗯, 还是目前看后序遍历足够了 orz
if (method) {
method(node, parent)
}
}
traverseNode(ast, null)
}
module.exports = { traverser, executeAST }
ast.js // 仅改动的函数
ExpressionStatement(node, parent) {
const parenStart = node.params.findIndex(p =>
p.type === 'ParenIdentifier' && p.value === '('
)
const parenEnd = node.params.findIndex(p =>
p.type === 'ParenIdentifier' && p.value === ')'
)
if (parenStart > -1 && parenEnd > -1) {
node.callee = { type: 'CallExpression' }
node.callee.arguments = node.params.slice(parenStart + 1, parenEnd)
node.callee.property = node.params[0]
delete node.params
return
}
// 函数调用也是很麻烦的事情, 先不管, 这次主要是数据类型 orz
const objIdx = node.params.findIndex(p =>
p.type === 'OperatorIdentifier' && p.value === '.'
)
const calleeIdx = node.params.findIndex(p =>
p.type === 'ExpressionStatement' && p.callee
)
// 临时处理括号深度问题 T T
if (parenEnd > -1) {
node.callee = { type: 'CallExpression' }
node.callee.arguments = [node.params[0]]
delete node.params
return
}
if (parenStart > -1 && calleeIdx > -1) {
node.callee = node.params[calleeIdx].callee
node.callee.property = node.params[0]
delete node.params
return
}
if (objIdx > -1 && calleeIdx > -1) {
node.object = { type: 'MemberExpression', value: node.params[objIdx -1 ]}
node.callee = node.params[calleeIdx].callee
delete node.params
return
}
},
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!