自制前端框架Web前端之路让前端飞

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

2017-05-12  本文已影响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

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流程:

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嵌套了两层,比较不爽,所以重新整一下逻辑:

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);
  })
测试案例截图

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

上一篇 下一篇

猜你喜欢

热点阅读