章节5:计算”1+1”词法解析

32 阅读1分钟

TokenType 词性枚举类

public enum TokenType {
    INTEGER // 数字
    , PLUS // 加法运算符
    , EOF // 程序结束
}

Token 词法单元

// 词法单元
@Data
public class Token {
    // 词性
    private TokenType type;
    // 词值
    private Object value;
    // 构造函数
    public Token(TokenType type , Object value){
        this.type = type;
        this.value = value;
    }
    // 构造函数
    public Token(TokenType type){
        this.type = type;
    }
}

词法解析器

// 词法解析器
public class Lexer {
    private String text; // 输入的程序
    private Integer position; // 记录扫描的位置
    private Character currentChar; // 记录当前扫描的字符
   
    public Token getNextToken(){  // 获取词法单元
        if(this.currentChar == null){ // 扫描完了结束
            return new Token(TokenType.EOF); 
        }else if(Character.isDigit(this.currentChar)){
            Token token = new Token(TokenType.INTEGER ,Character.getNumericValue(this.currentChar));
            this.advance();
            return token;
        }else if(this.currentChar == '+'){
            Token token = new Token(TokenType.PLUS , "+");
            this.advance();
            return token; 
        }else {
            this.error("未知的词法");
        }
        return new Token(TokenType.EOF); 
    }
    public void advance(){ // 往后走一步
        this.position += 1;
        if(this.position <= this.text.length() - 1){ // 扫描的位置有效
            this.currentChar = text.charAt(this.position);
        }else{ // 扫描完了
            this.currentChar = null;
        }
        
    }
    public void error(String msg){ // 报错函数
        throw new RuntimeException(msg);
    }
    public Lexer(String text) {// 构造器
        this.text = text;
        this.position = 0;
        this.currentChar = text.charAt(this.position);
    }
}
  • 变量text:存储程序文本。变量position和currentChar:词法解析器是顺序逐个扫描,所以创建position记录当前位置,currentChar记录当前字符。
  • 函数advance:每扫描一个字符,往后移动,直到末尾。
  • 函数error: 扫描到了未知的字符就会抛出异常信息。
  • 函数getNextToken:获取词法单元并向后移动,按照判断逻辑构建词法单元。

单元测试:

public static void main(String[] args) {
    Lexer lexer = new Lexer("1+1");
    Token token = lexer.getNextToken();
    while (token.getType() != TokenType.EOF) {
        System.out.println(token);
        token = lexer.getNextToken();
    }
}
测试结果:
Token(type=INTEGER, value=1) 
Token(type=PLUS, value=+) 
Token(type=INTEGER, value=1)