基于Python编写个语法解析器

news2024/9/28 9:11:28

这篇文章主要为大家详细介绍了如何基于Python编写个语法解析器,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下

目录
  • 前言
  • 选型
  • 效果
  • 实现
    • 字符指针
    • 错误类型
    • 语法解析
    • 交互

前言

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

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

选型

针对人群

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

目标

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

技术实现

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

本文目标

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

效果

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

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

实现

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

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

1

2

3

4

5

6

7

8

9

10

TT_INT = "整数"

TT_FLOAT = "浮点数"

TT_PLUS = "加号"

TT_DIV = "除号"

TT_MINUS = "减号"

TT_LPAREN = "左括号"

TT_RPAREN = "右括号"

TT_MUL = "乘"

TT_POWER = "次幂"

DIGITS = "123456789"

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

1

2

3

4

5

6

7

8

9

10

11

12

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,那么就要去读取解析文本,这个没有办法,我们只能一个字符一个字符进行扫描。为了方便,因此,这里对字符指针进行一个简单封装。

1

2

3

4

5

6

7

8

9

10

11

12

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一样:

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

"""

顶级错误(老大)

"""

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)

语法解析

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

"""

语法解析器

"""

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起来:

1

2

3

4

5

6

7

"""

语言解析,运行入口

"""

def run(fn, text):

    lexer = Lexer(fn, text)

    tokens, error = lexer.make_tokens()

    return tokens, error

交互

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

1

2

3

4

5

6

7

8

9

10

"""

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编写个语法解析器的详细内容。

点击拿去
50G+学习视频教程
100+Python初阶、中阶、高阶电子书籍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/887731.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

26、springboot的自动配置03--核心功能--自定义条件注解及使用

开发自己的自动配置------开发自己的条件注解 ★ 自定义条件注解 好处有两个&#xff1a; 1. 真正掌握Spring boot条件注解的本质。 2. 项目遇到一些特殊的需求时&#xff0c;也可以开发自己的自定义条件注解来解决问题。自定义条件注解&#xff1a; ▲ 所有自定义注解其实都…

香港服务器三网直连内地线路什么意思?好用吗?

​  三网直连内地是指香港服务器可以直接连接中国内地的电信、联通和移动三大运营商网络&#xff0c;避免了中间网络干线的支持。这样可以实现直接、快速、稳定的网络访问&#xff0c;提高用户对网络访问的效率&#xff0c;减少网络访问问题和拥堵的现象。 香港服务器直连内地…

开源项目AJ-Captcha使用小结

在网上看到开源项目AJ-Captcha&#xff0c;想把它加入到自己的项目中&#xff0c;遇到了一些问题&#xff0c;记录一下。 AJ-Captcha: 行为验证码(滑动拼图、点选文字)&#xff0c;前后端(java)交互&#xff0c;包含vue/h5/Android/IOS/flutter/uni-app/react/php/go/微信小程…

C# 读取pcd点云文件数据

pcd文件有ascii 和二进制格式&#xff0c;ascii可以直接记事本打开&#xff0c;C#可以一行行读。但二进制格式的打开是乱码&#xff0c;如果尝试程序中读取&#xff0c;对比下看了数据也对不上。 这里可以使用pcl里的函数来读取pcd&#xff0c;无论二进制或ascii都可以正确读取…

Fortinet数据中心防火墙及服务ROI超300%,Forrester TEI研究发布

近日&#xff0c;专注网络与安全融合的全球网络安全领导者 Fortinet&#xff08;NASDAQ&#xff1a;FTNT&#xff09;联合全球知名分析机构Forrester发布总体经济影响独立分析报告&#xff0c;详细阐述了在企业数据中心部署 FortiGate 下一代防火墙&#xff08;NGFW&#xff09…

web集群学习:搭建 LNMP应用环境

目录 LNMP的介绍&#xff1a; LNMP组合工作流程&#xff1a; FastCGI介绍&#xff1a; 1、什么是 CGI 2、什么是 FastCGI 配置LNMP 1、部署LNMP环境 2、配置LNMP环境 LNMP的介绍&#xff1a; 随着 Nginx Web 服务的逐渐流行&#xff0c;又岀现了新的 Web 服务环境组合—…

Ae 效果:CC WarpoMatic

过渡/CC WarpoMatic Transition/CC WarpoMatic CC WarpoMatic&#xff08;CC 自动扭曲&#xff09;主要用于创建动态的扭曲和弯曲过渡效果&#xff0c;可以在两个图层之间生成独特的过渡动画。 ‍ 这个效果允许用户根据特定的图层特性&#xff08;如亮度、对比度差异、亮度差异…

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)九:自定义组件封装下

一、本章内容 续上一张,本章实现一些自定义组件的封装,包括文件上传组件封装、级联选择组件封装、富文本组件封装等。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 基于VUE3+Layui从头搭建通用后台管

什么是大数据测试?有哪些类型?应该怎么测?

随着目前世界上各个国家使用大数据应用程序或应用大数据技术场景的数量呈指数增长&#xff0c;相应的&#xff0c;对于测试大数据应用时所需的知识与大数据测试工程师的需求也在同步增加。 针对大数据测试的相关技术已慢慢成为当下软件测试人员需要了解和掌握的一门通用技术。…

vue 安装并配置vuex

1.安装vuex命令:npm i vuex3.6.2 2.全局配置 在main文件里边导入-安装-挂载 main.js页面配置的 import Vue from vue import App from ./App.vue import Vuex from vuex//导入 Vue.use(Vuex)//安装插件 // 创建store对象 const store new Vuex.Store({ }) // 挂载到vue对象上…

ClickHouse AST is too big 报错问题处理记录

ClickHouse AST is too big 报错问题处理记录 问题描述问题分析解决方案1、修改系统配置2、修改业务逻辑 问题描述 项目中统计报表的查询出现 AST is too big 问题&#xff0c;报错信息如下&#xff1a; 问题分析 报错信息显示 AST is too big。 AST 表示查询语法树中的最大…

7-3 求给定精度的简单交错序列部分和

分数 15 全屏浏览题目 切换布局 作者 C课程组 单位 浙江大学 本题要求编写程序&#xff0c;计算序列部分和 1 - 1/4 1/7 - 1/10 ... 直到最后一项的绝对值不大于给定精度eps。 输入格式: 输入在一行中给出一个正实数eps。 输出格式: 在一行中按照“sum S”的格式输出…

2023年排行前五的大规模语言模型(LLM)

2023年排行前五的大规模语言模型(LLM) 截至2023年&#xff0c;人工智能正在风靡全球。它已经成为热门的讨论话题&#xff0c;吸引了数百万人的关注&#xff0c;不仅限于技术专家和研究人员&#xff0c;还包括来自不同背景的个人。人们对人工智能热情高涨的原因之一是其在人类多…

新版本Qt Creator无法提示错误、不报红

问题 更新新版本Qt Creator后无法实时提示错误&#xff0c;在开发中非常难受 如图&#xff0c;此时w后面少了;Qt Creator却只有红色横线标识&#xff0c;没有具体的错误。 解决方法 首先要知道&#xff0c;提供这个错误显示功能是ClangCodeModel插件提供的&#xff0c;因此…

Kafka-eagle监控平台

Kafka-Eagle简介 在开发工作中&#xff0c;当业务不复杂时&#xff0c;可以使用Kafka命令来进行一些集群的管理工作。但如果业务变得复杂&#xff0c;例如&#xff1a;需要增加group、topic分区&#xff0c;此时&#xff0c;再使用命令行就感觉很不方便&#xff0c;此时&#x…

FPGA_学习_15_IP核_VIO

前一篇博客我们提到在线调试的时候&#xff0c; 可执行文件只要烧进板子&#xff0c;程序它就会自己跑起来&#xff0c;不会等你点 这个按钮&#xff0c;它才开始跑。我们测试的模块中&#xff0c;里面可能有几个我们关心的信号&#xff0c;它会在程序刚运行很短的时间内发生状…

matlab初

matlab语言方式与c有很大的相似之处&#xff0c;此篇记录一下自己初步学习matlab的一些过程和代码 学习matlab主要是从b站上&#xff0c;也从matlab官网去学习了一下相关感兴趣的函数 版本是之前下好的R2022b 1.变量命名&#xff0c;这与c语言变量命名要求的规则非常相似 简单…

Pycharm与Anaconda Python的开发环境搭建

目录 一&#xff1a;下载 二&#xff1a;安装python 三&#xff1a;设置Pycharm 一&#xff1a;下载 下载Anaconda&#xff1a; Anaconda | The World’s Most Popular Data Science Platform 安装好以后&#xff0c;设置一下环境变量&#xff1a; 打开命令行&#xff0c…

双链表的插入,删除以及遍历

在上一节我们讲解了单链表的头插法和尾插法 http://t.csdn.cn/RixAu 但是单链表无法反向检索&#xff0c;对于某些情景可能造成不便&#xff0c;所以我们今天学习双链表 目录 1.双链表的初始化 2.双链表的插入 3.双链表的删除 4.遍历双链表 1.双链表的初始化 typedef i…

【Git】(一)基本操作

读完本文后&#xff0c;您会了解&#xff1a; 1、如何在本地配置GIT环境&#xff1f; 2、环境配置成功后&#xff0c;如何从远端下载一个已有仓库到本地? 1. 配置全局用户名、邮箱 git config --global user.name "username" git config --global user.email &q…