这篇文章主要为大家详细介绍了如何基于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初阶、中阶、高阶电子书籍