基于Python编写个语法解析器

 更新时间:2023年07月30日 10:20:48   作者:Huterox  
这篇文章主要为大家详细介绍了如何基于Python编写个语法解析器,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下

前言

目的纯粹,基于Python做一个简单的新的简单的编程语言。一方面是开拓视野,另一方面是作为毕设的临时过渡方案(没错,先前提到的算法平台,没有把握快速开发完毕,即便我使用大量的脚手架完成开发,但是算法容器,rpc算法调度中间件都需要自己造轮子,难度较大,此外还有用户部分的UI设计等等,最重要的是,那帮老师根本无法理解这种项目。没有必要搞太“花里胡哨”但是尽管如此,这个项目我后期还是要开发的,主要原因在于算法容器和rpc算法调度中间件,这个对我来说是非常值得去做的。里面涉及到的思想是非常受用的。虽然我现在在脑子里面构思好了,要怎么做,但是这个编码量实在太大。并且目标院校改考11408,现在导致我很被动,因此,我决定写一个sample computer language。同时为了加快开发进度,直接使用Python进行编写,后期转到Pypy,然后编译出这个语言的编译器。

那么目标的话,就是做到简单,直接做中文的,给小孩子锻炼思维的。当然,这也是为了方便给我讲故事。能在那帮尸位素餐的老师面前多说点他们能够理解的东西。没办法一个普通院校,很多老师水平也就那样,很无奈,但是没有办法改变。

选型

针对人群

有样没样,样子要像,那么这个编程语言的主要目的话,就是易学易用。推出中文编程,兼容Python,方便培养小学生锻炼编程思维,适合一到两年级的小学生进行学习。不同于图形化编程,Hlang可以体验到更加真实的编程环境,并且不会增加难度。既可以培养孩子的逻辑思维,同时还可以。。。 算了,编不下去了,就是个dome,同时用来应付应付毕设。

目标

没有目标,就是混~~ 本文目标,实现一个简单的语法解析器。反正随便写个几千行代码就能交个差,一帮混子!

技术实现

基于Python,体现体现思想,不追求运行效率,重在好学,给小孩子玩玩儿。不是总有某些家长说啥,英语难计算机简单的嘛?来,那就用用这个~~

本文目标

写一个简单的语法解析器,然后下班~ 高数玩腻了,就玩这个,这个玩腻了就学英语。

效果

ok,我们先来看到我们的实现效果:

这个就是一个简易的语法解析器。

实现

扯远了,我们来看看是如何进行实现的。

首先是定义好我们的标准合法字符:

TT_INT = "整数"
TT_FLOAT = "浮点数"
TT_PLUS = "加号"
TT_DIV = "除号"
TT_MINUS = "减号"
TT_LPAREN = "左括号"
TT_RPAREN = "右括号"
TT_MUL = "乘"
TT_POWER = "次幂"
DIGITS = "123456789"

然后我们定义一个Token把这些对象封装起来

class Token:
    def __init__(self,is_type,is_value=None):
        self.is_type = is_type
        self.is_value = is_value
    def __repr__(self):
        if self.is_value:
            return "|类型:{},值:{}|".format(self.is_type,self.is_value)
        return "|类型:{}|".format(self.is_type)
    def __str__(self):
        if(self.is_value):
            return "|{}|".format(self.is_value)
        return "|这个对象没有值,类型为:{}|".format(self.is_type)

在这里我们要做的目的很简单,那就是,把接下来输入的内容,或者文本内容,进行读取,然后解析出东西,把合法的字符收集起来。注意,我们这里还没有什么变量的概念,在这里只是负责解析好基本的合法字符。至于变量的引入要到后面,因为这个时候要设计清楚基本的语法规范,然后就是照着一顿借鉴就完了。

字符指针

之后的话,我们定义好了Token,那么就要去读取解析文本,这个没有办法,我们只能一个字符一个字符进行扫描。为了方便,因此,这里对字符指针进行一个简单封装。

class Position:
    def __init__(self, idx, ln, col):
        self.idx = idx
        self.ln = ln
        self.col = col
    def advance(self, cur_char):
        self.idx += 1
        self.col += 1
        if cur_char == '\n':
            self.ln += 1
            self.col = 0
        return self

错误类型

之后的话,我们还要去定义错误。比如,当我输入一个非法字符之后要报个错,就像Python一样:

所以我们也要来个这个东西:

"""
顶级错误(老大)
"""
class HlangError:
    def __init__(self, pos_ln,in_fn,error_name, details):
        """
        :param pos_ln: 错误行
        :param in_fn: 输入文件
        :param error_name: 错误名称
        :param details: 错误细节,说明
        """
        self.pos_ln = pos_ln
        self.in_fn = in_fn
        self.error_name = error_name
        self.details = details
    def as_string(self):
        red_code = "\033[91m"
        reset_code = "\033[0m"
        result = f'{self.error_name}: {self.details}\n'
        result += f'来自 {self.in_fn}, line {self.pos_ln + 1}'
        return red_code+result+reset_code
class IllegalCharError(HlangError):
    """
    非法字符错误
    """
    def __init__(self, pos_ln,in_fn, details):
        super().__init__(pos_ln, in_fn, '非法字符', details)

语法解析

那么之后的话,就可以开始我们的语法解析了

这个代码的话,很简单,就是往死里加入就好了

"""
语法解析器
"""
class Lexer:
    def __init__(self, in_fn, text):
        """
        :param in_fn: 从哪里输入的文本(文本所在文件,标准输入,输出也是一个文件)
        其实就是文件名~~~
        :param text: 待解析文本
        """
        self.in_fn = in_fn
        self.text = text
        self.pos = Position(-1, 0, -1)
        self.cur_char = None
        self.advance()
        #基本的符号处理
        self.char_pro_base = {
            '+':TT_PLUS,
            '-':TT_MINUS,
            '*':TT_MUL,
            '/':TT_DIV,
            '^':TT_POWER,
            '(':TT_LPAREN,
            ')':TT_RPAREN
        }
    def advance(self):
        self.pos.advance(self.cur_char)
        self.cur_char = self.text[self.pos.idx] if self.pos.idx < len(self.text) else None
    def __char_process(self,tokens,TT):
        """
        处理基本字符的方法,
        添加Token,并且移动字符指针
        :return:
        """
        tokens.append(Token(TT))
        self.advance()
    def make_tokens(self):
        """
        将文本当中的字符添加到语法解析器当中,将符合语法规范的内容,封装为Token,
        (就像Spring将对象信息再封装为Wapper一样,方便后续进行操作。)
        :return:
        """
        tokens = []
        while self.cur_char != None:
            if self.cur_char in ' \t':
                #制表符(空格),没有意义,往前移动
                self.advance()
            elif self.cur_char in DIGITS:
                #如果是数字,自动往前搜索,并且将数字进行添加,并且判断类型,
                #数字比较特殊,不是一个字符一个字符参与的(后面还要定义关键字也是类似的)
                tokens.append(self.make_number())
            else:
                TT = self.char_pro_base.get(self.cur_char)
                if(TT):
                    self.__char_process(tokens,TT)
                else:
                    char = self.cur_char
                    self.advance()
                    return [], IllegalCharError(self.pos.ln,self.in_fn, "'" + char + "'")
        return tokens, None
    def make_number(self):
        num_str = ''
        dot_count = 0
        while self.cur_char != None and self.cur_char in DIGITS + '.':
            if self.cur_char == '.':
                if dot_count == 1: break
                dot_count += 1
                num_str += '.'
            else:
                num_str += self.cur_char
            self.advance()
        if dot_count == 0:
            return Token(TT_INT, int(num_str))
        else:
            return Token(TT_FLOAT, float(num_str))

之后的话,别忘了还需要要一个run作为入口,run起来:

"""
语言解析,运行入口
"""
def run(fn, text):
    lexer = Lexer(fn, text)
    tokens, error = lexer.make_tokens()
    return tokens, error

交互

最后的最后,就是我们的交互了:

"""
Hlang is a Sample Language shell
Just a sample example for learning by Huterox
"""
import basic
while True:
    input_text = input("交互终端:")
    result, error = basic.run('<标准输入>', input_text)
    if error: print(error.as_string())
    else: print(result)

然后搞定,so 简单

以上就是基于Python编写个语法解析器的详细内容,更多关于Python语法解析器的资料请关注脚本之家其它相关文章!

相关文章

  • 利用Python如何实现一个小说网站雏形

    利用Python如何实现一个小说网站雏形

    这篇文章主要给大家介绍了关于利用Python如何实现一个小说网站雏形的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用python具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-11-11
  • python验证多组数据之间有无显著差异

    python验证多组数据之间有无显著差异

    这篇文章主要介绍了python验证多组数据之间有无显著差异,利用方差分析和卡方分布验证多组数据之间的某些属性有无显著性差异,对于连续性属性可以用方差分析,对于离散型属性可以用卡方检验。下面文章详细内容需要的小伙伴可以参考一下
    2022-01-01
  • 基于Pydantic封装的通用模型在API请求验证中的应用详解

    基于Pydantic封装的通用模型在API请求验证中的应用详解

    这篇文章主要介绍了基于Pydantic封装的通用模型在API请求验证中的应用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2023-05-05
  • Python 条件判断的缩写方法

    Python 条件判断的缩写方法

    开始以为Python中没有像其他语言一样的条件判断的缩写形式:
    2008-09-09
  • Python中字符串的基本使用详解

    Python中字符串的基本使用详解

    Python要求字符串必须使用引号括起来,使用单引号也行,使用双引号也行,只要两边的引号能配对即可,这篇文章主要给大家介绍了关于Python中字符串的基本使用,需要的朋友可以参考下
    2021-12-12
  • Python实现暴力破解wifi密码并打包成exe

    Python实现暴力破解wifi密码并打包成exe

    python号称是编程界的万金油,那么是否可以做个读取电脑网卡wifi并暴力破解的小脚本呢?在这个基础上为了方便体验是不是可以将其打包成exe这样方便执行的小应用呢?本文就来和大家一起聊聊
    2022-09-09
  • Python标准库re的使用举例(正则化匹配)

    Python标准库re的使用举例(正则化匹配)

    正则表达式re是内置函数,通过一定的匹配规则获取指定的数据,下面这篇文章主要给大家介绍了关于Python标准库re的使用举例,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-10-10
  • Python读写压缩文件的方法

    Python读写压缩文件的方法

    这篇文章主要介绍了Python读写压缩文件的方法,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • python:socket传输大文件示例

    python:socket传输大文件示例

    本篇文章主要介绍了python:socket传输大文件示例,具有一定的参考价值,有兴趣的可以了解一下,
    2017-01-01
  • Python 编码规范(Google Python Style Guide)

    Python 编码规范(Google Python Style Guide)

    本项目并非 Google 官方项目, 而是由国内程序员凭热情创建和维护,对于想学习python的朋友可以参考一下
    2018-05-05

最新评论