美文网首页自制前端框架Web前端之路让前端飞
自制前端框架 Day4. 编译科学计数和小数

自制前端框架 Day4. 编译科学计数和小数

作者: 蚊子爸爸 | 来源:发表于2017-05-12 16:17 被阅读25次

前面的几天写了一个小编译器,可以编译一个整数表达式,可是这还不够。拿数字来说,还有小数和科学计数法。所以今天我打算把这个功能给加上。
其实加小数这个功能贼容易,按照之前的思路,如果遇到是数字的就进入readNumber流程,在这个流程中,判断每个字符是不是数字,是的话就拼起来,不是就跳出。现在只需要加上小数点就行。只需要修改readNumber方法就可以:

Lexer.prototype.readNumber=function(){
  var token;
  var number='';
  while (this.index<this.text.length) {
    var currentChar = this.text.charAt(this.index);
    if(this.isNumber(currentChar)||currentChar==="."){
      number+=currentChar;
      this.index++;
    }else{
      break;
    }
  }
  token={
    text:number,
    value:Number(number)
  }
  this.tokens.push(token)
}

这样写没毛病,测试案例也过去了。写科学计数其实也容易,逻辑理顺了就行,比如这样的:
23e+3

  • e的后面只能是加号或者减号或者数字,否则就报错。
  • 加号或者减号的后面必须有数字,否则就报错。
    先写一个方法,用来判断一个字符是否可以放在E后面:
Lexer.isExOprater=function(char){
  return char==="+"||char==="-"||this.isNumber(char);
}

还要写一个方法用来读取当前字符的下一个字符是什么:

Lexer.prototype.peek=function(){
      if(this.index<this.text.length-1){
        return this.text.charAt(this.index+1);
      }else{
        return false;
      }
}

接下来就是把逻辑理清楚,去完善readNumber流程:

  • 当前字符是e,下一个字符是+或者-或者是数字,正常通行。
  • 当前字符是e或者+或者-,没有下一个字符,报错。
  • 当前字符是e或者+或者-,下一个字符是数字,通行。
  • 当前字符是e或者+或者-,下一个字符不是数字,报错。
    按照这个逻辑写了代码:
Lexer.prototype.readNumber=function(){
  var token;
  var number='';
  while (this.index<this.text.length) {
    var currentChar = this.text.charAt(this.index).toLowerCase();
    var nextChar = this.peek();
    if(this.isNumber(currentChar)||currentChar==="."){
      number+=currentChar;
      this.index++;
    }else if (currentChar==="e"&&nextChar&&this.isExOprater(nextChar)) {
      number+=currentChar;
      this.index++;
    }else if (this.isExOprater(currentChar)&&nextChar) {
      if (this.isNumber(nextChar)) {
        number+=currentChar;
        this.index++;
      }else{
        throw "readNumber流程出错:e或者+或者-后面只能是数字"
      }
    }else if (this.isExOprater(currentChar)&&!nextChar) {
      throw "readNumber流程出错:e或者+或者-后面都需要有字符"
    }else{
      break;
    }
  }
  token={
    text:number,
    value:Number(number)
  }
  this.tokens.push(token)
}

这个代码if嵌套了两层,比较不爽,所以重新整一下逻辑:

  • 当前字符是e,下一个字符是+或者-或者数字,通过
  • 前面是e,下一个是数字,自身是+或者-或者数字,通过。
  • 前面是e,自身是+或者-或者数字,后面不是数字或者没有字符,报错。
    这个逻辑也没毛病,而且判断比之前少了一个,可以。修改代码:
Lexer.prototype.readNumber=function(){
  var token;
  var number='';
  while (this.index<this.text.length) {
    var currentChar = this.text.charAt(this.index).toLowerCase();
    var nextChar = this.peek();
    var prevChar = this.text.charAt(this.index-1);
    if(this.isNumber(currentChar)||currentChar==="."){
      number+=currentChar;
      this.index++;
    }else if (currentChar==="e"&&nextChar&&this.isExOprater(nextChar)) {
      number+=currentChar;
      this.index++;
    }else if (prevChar==='e'&&this.isExOprater(currentChar)&&nextChar&&this.isNumber(nextChar)) {
      number+=currentChar;
      this.index++;
    }else if (prevChar==='e'&&this.isExOprater(currentChar)&&(!nextChar||!this.isNumber(nextChar))) {
      throw "readNumber流程出错:不合法的输入"
    }else{
      break;
    }
  }
  token={
    text:number,
    value:Number(number)
  }
  this.tokens.push(token)
}

搞定,测试案例也都通过:

it("可以编译一个以小数点结尾的数",function(){
    var expression = '233.';
    var lexer = new Lexer();
    var astbuilder = new ASTBuilder(lexer);
    var compiler = new Compiler(astbuilder);
    var FnA = compiler.compile(expression);
    expect(FnA()).toBe(233);
  })
  it("可以编译格式如2.33e+2这样的科学计数",function() {
    var expression = '2.33e+2';
    var lexer = new Lexer();
    var astbuilder = new ASTBuilder(lexer);
    var compiler = new Compiler(astbuilder);
    var FnA = compiler.compile(expression);
    expect(FnA()).toBe(233);
  })
  it("可以编译格式如233e-2这样的科学计数",function() {
    var expression = '233e-2';
    var lexer = new Lexer();
    var astbuilder = new ASTBuilder(lexer);
    var compiler = new Compiler(astbuilder);
    var FnA = compiler.compile(expression);
    expect(FnA()).toBe(2.33);
  })
  it("可以编译格式如233e2这样的科学计数",function() {
    var expression = '233e2';
    var lexer = new Lexer();
    var astbuilder = new ASTBuilder(lexer);
    var compiler = new Compiler(astbuilder);
    var FnA = compiler.compile(expression);
    expect(FnA()).toBe(23300);
  })
测试案例截图

很烦很烦,今天写代码写的不爽,本以为分分钟就能写完的东西让我写了这么久。两个多小时,烦烦烦。

相关文章

网友评论

    本文标题:自制前端框架 Day4. 编译科学计数和小数

    本文链接:https://www.haomeiwen.com/subject/ajgztxtx.html