用 Python 实现一门脚本语言

最近利用业余的时间实践了下编译原理,约 4200 行 python 实现了一个简单的脚本语言(类 C )。含括了数组、字典、闭包、模块等常用的功能,奉上 github https://github.com/roy2220/oyc,有兴趣的小伙伴一起讨论交流!


用 Python 实现一门脚本语言
3 回复

要实现一门脚本语言,核心是构建解释器。这里提供一个最简示例,实现支持四则运算和变量的脚本语言。

import re

class Token:
    def __init__(self, type, value):
        self.type = type
        self.value = value

class Lexer:
    def __init__(self, text):
        self.text = text
        self.pos = 0
        self.current_char = self.text[self.pos] if self.text else None
    
    def advance(self):
        self.pos += 1
        self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
    
    def skip_whitespace(self):
        while self.current_char and self.current_char.isspace():
            self.advance()
    
    def integer(self):
        result = ''
        while self.current_char and self.current_char.isdigit():
            result += self.current_char
            self.advance()
        return int(result)
    
    def get_next_token(self):
        while self.current_char:
            if self.current_char.isspace():
                self.skip_whitespace()
                continue
            
            if self.current_char.isdigit():
                return Token('INTEGER', self.integer())
            
            if self.current_char.isalpha():
                identifier = ''
                while self.current_char and (self.current_char.isalnum() or self.current_char == '_'):
                    identifier += self.current_char
                    self.advance()
                return Token('IDENTIFIER', identifier)
            
            if self.current_char == '=':
                self.advance()
                return Token('ASSIGN', '=')
            
            if self.current_char in '+-*/':
                op = self.current_char
                self.advance()
                return Token('OPERATOR', op)
            
            if self.current_char == '(':
                self.advance()
                return Token('LPAREN', '(')
            
            if self.current_char == ')':
                self.advance()
                return Token('RPAREN', ')')
            
            raise Exception(f'Invalid character: {self.current_char}')
        
        return Token('EOF', None)

class Parser:
    def __init__(self, lexer):
        self.lexer = lexer
        self.current_token = self.lexer.get_next_token()
        self.variables = {}
    
    def eat(self, token_type):
        if self.current_token.type == token_type:
            self.current_token = self.lexer.get_next_token()
        else:
            raise Exception(f'Expected {token_type}, got {self.current_token.type}')
    
    def factor(self):
        token = self.current_token
        
        if token.type == 'INTEGER':
            self.eat('INTEGER')
            return token.value
        
        if token.type == 'IDENTIFIER':
            var_name = token.value
            self.eat('IDENTIFIER')
            if var_name not in self.variables:
                raise Exception(f'Undefined variable: {var_name}')
            return self.variables[var_name]
        
        if token.type == 'LPAREN':
            self.eat('LPAREN')
            result = self.expr()
            self.eat('RPAREN')
            return result
        
        raise Exception(f'Unexpected token: {token.type}')
    
    def term(self):
        result = self.factor()
        
        while self.current_token.type == 'OPERATOR' and self.current_token.value in '*/':
            token = self.current_token
            self.eat('OPERATOR')
            
            if token.value == '*':
                result *= self.factor()
            else:
                result /= self.factor()
        
        return result
    
    def expr(self):
        result = self.term()
        
        while self.current_token.type == 'OPERATOR' and self.current_token.value in '+-':
            token = self.current_token
            self.eat('OPERATOR')
            
            if token.value == '+':
                result += self.term()
            else:
                result -= self.term()
        
        return result
    
    def assignment(self):
        var_name = self.current_token.value
        self.eat('IDENTIFIER')
        self.eat('ASSIGN')
        value = self.expr()
        self.variables[var_name] = value
        return value
    
    def parse(self):
        if self.current_token.type == 'IDENTIFIER' and self.lexer.current_char == '=':
            return self.assignment()
        return self.expr()

def interpret(code):
    lexer = Lexer(code)
    parser = Parser(lexer)
    return parser.parse()

# 测试示例
if __name__ == '__main__':
    # 基本运算
    print(interpret("2 + 3 * 4"))  # 输出: 14
    
    # 带括号
    print(interpret("(2 + 3) * 4"))  # 输出: 20
    
    # 变量赋值和使用
    interpret("x = 10")
    interpret("y = 20")
    print(interpret("x + y"))  # 输出: 30
    
    # 复杂表达式
    interpret("a = 5")
    interpret("b = 3")
    print(interpret("(a + b) * 2 - b / 1"))  # 输出: 13.0

这个实现包含了词法分析器(Lexer)、语法分析器(Parser)和解释器。词法分析器将源代码转换为token流,语法分析器构建抽象语法树并执行计算。支持整数、四则运算、括号和变量赋值。

要扩展功能,可以添加:1)更多数据类型(字符串、布尔值);2)控制结构(if/while);3)函数定义;4)错误处理。

总结:从词法分析和语法分析开始构建。


大佬…

花点时间撸一撸,你也是大佬:)

回到顶部