-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
js写的一个简单四则运算解释器 #13
Comments
本文主要分为三个部分
|
语法定义
<Expression> ::=
<AdditiveExpression><EOF>
<AdditiveExpression> ::=
<MultiplicativeExpression>
|<AdditiveExpression><+><MultiplicativeExpression>
|<AdditiveExpression><-><MultiplicativeExpression>
<MultiplicativeExpression> ::=
<Number>
|<MultiplicativeExpression><*><Number>
|<MultiplicativeExpression></><Number> |
词法分析
'1 + 2' => [{type: 'Number', value: 1}, {type: '+', value: '+'}, {type: 'Number', value: 2}];
const start = char => {
if (['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'].includes(char)) {
token.push(char);
return inNumber;
}
// 支持负数
if (char === '-') {
if (tokens.length === 0 || ['+', '-', '*', '/'].includes(tokens[tokens.length - 1].type)) {
token.push(char);
return inNumber;
}
}
if (['+', '-', '*', '/'].includes(char)) {
emmitToken(char, char);
return start
}
if (char === ' ') {
return start;
}
if (['\r', '\n'].includes(char)) {
return start;
}
// EOF 表示结束
if (char === 'EOF') {
emmitToken(char, char);
return start;
}
}
const inNumber = char => {
// 支持小数
if (['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.'].includes(char)) {
token.push(char);
return inNumber;
} else {
emmitToken("Number", token.join(''));
token=[];
return start(char);
}
} 接下来运行一下 const input = '1 + 1 * 2';
let state = start;
for(let c of input.split('')) {
state = state(c);
}
state('EOF'); 我们会得到如下的token数组 0: {type: "Number", value: "1"}
1: {type: "+", value: "+"}
2: {type: "Number", value: "1"}
3: {type: "*", value: "*"}
4: {type: "Number", value: "2"}
5: {type: "EOF", value: "EOF"} 词法分析到此就结束了,接下来就是根据token流生成ast |
语法分析
/**
* <AdditiveExpression> ::=
* <MultiplicativeExpression>
* |<AdditiveExpression><+><MultiplicativeExpression>
* |<AdditiveExpression><-><MultiplicativeExpression>
*/
const AdditiveExpression = (source) => {
if(source[0].type === "MultiplicativeExpression") {
let node = {
type: 'AdditiveExpression',
children: [source[0]],
};
source[0] = node;
return AdditiveExpression(source);
}
if(source[0].type === 'AdditiveExpression' && source[1] && source[1].type === '+') {
let node = {
type: 'AdditiveExpression',
operator: '+',
children: [source.shift(), source.shift()],
}
MultiplicativeExpression(source);
node.children.push(source.shift());
source.unshift(node);
return AdditiveExpression(source);
}
if (source[0].type === 'AdditiveExpression' && source[1] && source[1].type === '-') {
let node = {
type: 'AdditiveExpression',
operator: '-',
children: [source.shift(), source.shift()],
}
MultiplicativeExpression(source);
node.children.push(source.shift());
source.unshift(node);
return AdditiveExpression(source);
}
if (source[0].type === 'AdditiveExpression') {
return source[0];
}
MultiplicativeExpression(source);
return AdditiveExpression(source);
}
{
children: (2) [{
children: (3) [{
type: "AdditiveExpression",
children: [
{type: "MultiplicativeExpression", operator: "*", children: [{2..}, {*...}, {1...}]}
]}
{type: "+", value: "+"},
{type: "MultiplicativeExpression", children: [{type: "Number", value: "1"}],
}],
operator: "+"
type: "AdditiveExpression"
}, {
type: "EOF"
value: "EOF"
}],
type: "Expression"
} |
解释执行得到ast之后,就是解释执行了。后序遍历ast求值即可 function evaluate(node) {
if (node.type === 'Expression') {
return evaluate(node.children[0]);
}
if (node.type === 'AdditiveExpression') {
if(node.operator === '-') {
return evaluate(node.children[0]) - evaluate(node.children[2]);
}
if(node.operator === '+') {
return evaluate(node.children[0]) + evaluate(node.children[2]);
}
return evaluate(node.children[0]);
}
if(node.type === 'MultiplicativeExpression') {
if (node.operator === '*') {
return evaluate(node.children[0]) * evaluate(node.children[2]);
}
if (node.operator === '/') {
return evaluate(node.children[0]) * evaluate(node.children[2]);
}
return evaluate(node.children[0]);
}
if (node.type === 'Number') {
return Number(node.value);
}
} 到此为止我们实现了一个支持负数与小数的四则运算编译器。以后还会增加括号功能 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
No description provided.
The text was updated successfully, but these errors were encountered: