Skip to content
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

【每日一题】- 2020-05-16 - 解析字符串 #128

Closed
azl397985856 opened this issue May 16, 2020 · 5 comments
Closed

【每日一题】- 2020-05-16 - 解析字符串 #128

azl397985856 opened this issue May 16, 2020 · 5 comments

Comments

@azl397985856
Copy link
Owner

azl397985856 commented May 16, 2020

给你一个字符串if (x > 5) { console.log('greater than 5')} else { console.log('less than 5')}

预期:

let a = 1;
const sourceCode = "if (x > 5) { console.log('greater than 5')} else { console.log('less than 5')}";
function eval(text) {
   // do something
}

eval(souceCode) // 'less than 5'
a = 6
eval(souceCode) // 'great than 5'

要求:

  • 不能使用eval, script 标签 或者 new Function
@feikerwu
Copy link
Contributor

一个比较挫的想法,放入到script执行🤓🤓🤓

function eval(sourceCode) {
  const reg = /(?<=[\[\(\{\s])x(?=[\[\(\{\s])/
  sourceCode = sourceCode.replace(reg, 'a')
  const script = document.createElement('script')
  script.type = 'text/javascript'
  script.innerHTML = sourceCode
  document.body.appendChild(script)
}

@azl397985856
Copy link
Owner Author

@feikerwu 😂 不准用script 标签, 我改下题目描述

@feikerwu
Copy link
Contributor

说下想法,在不用Function,eval, script 的前提下,我们要去执行给定的一段字符,问题转化下其实就是

如何在不用原生提供的js解释器情况下去执行一段js脚本

那很朴素的想法就是,提供方不给执行,我们自己造一个解释器去跑不就好了,至于最后能不能造出来我们另说。所以问题再转化下就是

如何造一个解释器去执行上述提供的字符脚本

解释器就是一段程序,输入是sourcecode字符,程序功能是识别sourcecode内容,并做相应的处理,sourcecode由条件,循环,变量定义,运算等组成,但不管怎么样,这些功能都是可穷举的。
所以第一步就是将sourcecode翻译成上述的功能聚合,以计算机可识别的形式表示,编译原理天然的采用树的结果,或者说AST(Abstract Syntax Tree,抽象语法树),下面是用 acorn 将上述sourcecode转化出来的语法树表示

{
  "type": "Program",
  "start": 0,
  "end": 78,
  "body": [
    {
      "type": "IfStatement",
      "start": 0,
      "end": 78,
      "test": {
        "type": "BinaryExpression",
        "start": 4,
        "end": 9,
        "left": {
          "type": "Identifier",
          "start": 4,
          "end": 5,
          "name": "x"
        },
        "operator": ">",
        "right": {
          "type": "Literal",
          "start": 8,
          "end": 9,
          "value": 5,
          "raw": "5"
        }
      },
      "consequent": {
        "type": "BlockStatement",
        "start": 11,
        "end": 43,
        "body": [
          {
            "type": "ExpressionStatement",
            "start": 13,
            "end": 42,
            "expression": {
              "type": "CallExpression",
              "start": 13,
              "end": 42,
              "callee": {
                "type": "MemberExpression",
                "start": 13,
                "end": 24,
                "object": {
                  "type": "Identifier",
                  "start": 13,
                  "end": 20,
                  "name": "console"
                },
                "property": {
                  "type": "Identifier",
                  "start": 21,
                  "end": 24,
                  "name": "log"
                },
                "computed": false
              },
              "arguments": [
                {
                  "type": "Literal",
                  "start": 25,
                  "end": 41,
                  "value": "greater than 5",
                  "raw": "'greater than 5'"
                }
              ]
            }
          }
        ]
      },
      "alternate": {
        "type": "BlockStatement",
        "start": 49,
        "end": 78,
        "body": [
          {
            "type": "ExpressionStatement",
            "start": 51,
            "end": 77,
            "expression": {
              "type": "CallExpression",
              "start": 51,
              "end": 77,
              "callee": {
                "type": "MemberExpression",
                "start": 51,
                "end": 62,
                "object": {
                  "type": "Identifier",
                  "start": 51,
                  "end": 58,
                  "name": "console"
                },
                "property": {
                  "type": "Identifier",
                  "start": 59,
                  "end": 62,
                  "name": "log"
                },
                "computed": false
              },
              "arguments": [
                {
                  "type": "Literal",
                  "start": 63,
                  "end": 76,
                  "value": "less than 5",
                  "raw": "'less than 5'"
                }
              ]
            }
          }
        ]
      }
    }
  ],
  "sourceType": "module"
}

可以看到每个节点都有一个 type, 就是上面说的可穷举的程序节点,比如IfStatement(条件)Literal等等。

第二步,我们拿到上述AST之后,可以给每个type节点加一个处理函数,比如看到ifStatement怎么做,看到 console 的 Identifier 怎么做等等。

定义好每个节点的处理函数之后,从AST root遍历这棵树,对每个节点执行相应的函数

@azl397985856
Copy link
Owner Author

@feikerwu 非常棒。 就是这个意思

@azl397985856 azl397985856 pinned this issue May 19, 2020
@stale
Copy link

stale bot commented Jul 16, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jul 16, 2020
@stale stale bot closed this as completed Jul 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

2 participants