官方手册:http://www.dabeaz.com/ply/ply.html

以下例子都来自官方手册:

以四则运算为例: x = 3 + 42 * (s - t)

词法分析:

需要将其分解为:

'x','=', '3', '+', '42', '*', '(', 's', '-', 't', ')'

并且给每个部分起一个名字,标识这是什么东西。这些标识会用在后面的语法分析中。

('ID','x'), ('EQUALS','='), ('NUMBER','3'),
('PLUS','+'), ('NUMBER','42), ('TIMES','*'),
('LPAREN','('), ('ID','s'), ('MINUS','-'),
('ID','t'), ('RPAREN',')'

例子:

# ------------------------------------------------------------
# calclex.py
#
# tokenizer for a simple expression evaluator for
# numbers and +,-,*,/
# ------------------------------------------------------------
import ply.lex as lex # List of token names. This is always required
tokens = (
'NUMBER',
'PLUS',
'MINUS',
'TIMES',
'DIVIDE',
'LPAREN',
'RPAREN',
) # Regular expression rules for simple tokens
t_PLUS = r'\+'
t_MINUS = r'-'
t_TIMES = r'\*'
t_DIVIDE = r'/'
t_LPAREN = r'\('
t_RPAREN = r'\)' # A regular expression rule with some action code
def t_NUMBER(t):
r'\d+'
t.value = int(t.value)
return t # Define a rule so we can track line numbers
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value) # A string containing ignored characters (spaces and tabs)
t_ignore = ' \t' # Error handling rule
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1) # Build the lexer
lexer = lex.lex()

注意:

里面名字的命名格式是固定的,ID的名称必须叫tokens,每个ID具体的内容必须用t_ID来指定。

单个字符可以直接定义变量,复杂成分要用函数形式表示,并且一定要有一个该成分的正则表达式字符串

比如上面例子中,t_NUMBER函数中有一个r'\d+',这在一般的python程序中看起来没有意义,但是在ply中则是必须的!它指定了模块如何划分NUMBER。

更多注意事项参考官方手册。

具体使用:

# Test it out
data = '''
3 + 4 * 10
+ -20 *2
''' # Give the lexer some input
lexer.input(data) # Tokenize
while True:
tok = lexer.token()
if not tok:
break # No more input
print(tok)

结果:

$ python example.py
LexToken(NUMBER,3,2,1)
LexToken(PLUS,'+',2,3)
LexToken(NUMBER,4,2,5)
LexToken(TIMES,'*',2,7)
LexToken(NUMBER,10,2,10)
LexToken(PLUS,'+',3,14)
LexToken(MINUS,'-',3,16)
LexToken(NUMBER,20,3,18)
LexToken(TIMES,'*',3,20)
LexToken(NUMBER,2,3,21)

语法分析:

一个四则运算的语法结构是下面这个样子:

expression : expression + term
| expression - term
| term term : term * factor
| term / factor
| factor factor : NUMBER
| ( expression )

用ply实现四则运算语法分析:

# Yacc example

import ply.yacc as yacc

# Get the token map from the lexer.  This is required.
from calclex import tokens def p_expression_plus(p):
'expression : expression PLUS term'
p[0] = p[1] + p[3] def p_expression_minus(p):
'expression : expression MINUS term'
p[0] = p[1] - p[3] def p_expression_term(p):
'expression : term'
p[0] = p[1] def p_term_times(p):
'term : term TIMES factor'
p[0] = p[1] * p[3] def p_term_div(p):
'term : term DIVIDE factor'
p[0] = p[1] / p[3] def p_term_factor(p):
'term : factor'
p[0] = p[1] def p_factor_num(p):
'factor : NUMBER'
p[0] = p[1] def p_factor_expr(p):
'factor : LPAREN expression RPAREN'
p[0] = p[2] # Error rule for syntax errors
def p_error(p):
print("Syntax error in input!") # Build the parser
parser = yacc.yacc() while True:
try:
s = raw_input('calc > ')
except EOFError:
break
if not s: continue
result = parser.parse(s)
print(result)

与词法分析一样,语法分析的命名方式也是固定的 p_成分名_动作。

函数一开始必须是一个声明字符串,格式是 “成分名 :成分名 成分名 ...”  其中成分名可以是词法分析中的ID,比如上面的PLUS, NUMBER等等。冒号右边的是这个函数结果的成分名。即,语法分析通过组合各个ID得到结构化的结果。

成分相同的结构可以合并,如同时定义加法和减法

def p_expression(p):
'''expression : expression PLUS term
| expression MINUS term'''
if p[2] == '+':
p[0] = p[1] + p[3]
elif p[2] == '-':
p[0] = p[1] - p[3]

可以看到字符串的内容有变化,多余一种组合的用 | 换行分隔。注意这个字符串的格式是固定的,不过PLUS和MINUS的顺序没有影响,哪个在上面都可以。

更多细节,参见手册。

												

【python】词法语法解析模块ply的更多相关文章

  1. python命令行解析模块--argparse

    python命令行解析模块--argparse 目录 简介 详解ArgumentParser方法 详解add_argument方法 参考文档: https://www.jianshu.com/p/aa ...

  2. 编译impala、拓展impala语法解析模块

    以前也编译过,但是每次编译都忘记怎么做,然后都得重新找需要下载的文件. 编译文件:buildall.sh 如果想只编译前端可以这样运行: buildall.sh -fe_only 编译时会去S3下载一 ...

  3. python之参数解析模块argparse

    2.7之后python不再对optparse模块进行扩展,python标准库推荐使用argparse模块对命令行进行解析. 简单入门 先来看个例子: argparse_test.py: import ...

  4. python argparse(参数解析模块)

    这是一个参数解析,可以用它快捷的为你的程序生成参数相关功能 import argparse(导入程序参数模块) # 创建argparse对象,并将产品简要说明加入show = '程序说明' ===&g ...

  5. python optparse命令解析模块

    来源:http://www.cnblogs.com/pping/p/3989098.html?utm_source=tuicool&utm_medium=referral 来源:http:// ...

  6. Python 命令行解析模块 —— argparse

    argparse是python标准库里面用来处理命令行参数的库,基本使用步骤如下: 1.import argparse    导入模块 2.parser = argparse.ArgumentPars ...

  7. 【python基础语法】模块和包管理,文件的操作(第8天课堂笔记)

    ''' 模块和包管理 模块和包的定义: 模块:模块是一个Python文件,以.py结尾,包含了Python对象定义和Python语句 包:Python中的包就是一个包含__init__.py文件的目录 ...

  8. Python中配置文件解析模块-ConfigParser

    Python中有ConfigParser类,可以很方便的从配置文件中读取数据(如DB的配置,路径的配置).配置文件的格式是: []包含的叫section, section 下有option=value ...

  9. python命令行参数解析模块argparse和docopt

    http://blog.csdn.net/pipisorry/article/details/53046471 还有其他两个模块实现这一功能,getopt(等同于C语言中的getopt())和弃用的o ...

随机推荐

  1. Docker容器基础知识学习

    Docker作为操作系统层面的轻量级的虚拟化技术,凭借简易的使用.快速的部署以及灵活敏捷的集成等优势,迅速发展目前最为火热的技术. 1.云计算服务是一种资源管理的资源服务,该模式可以实现随时随地.便捷 ...

  2. 湖南附中模拟day1 收银员

    4.1 题意描述花花家的超市是 24 小时营业的,现在需要招聘收银员.超市每个小时都需要不同数量的收银员,用 ai 表示一天中 i 点到 i + 1 点这一小时内需要的收银员数量,特别地 a23 表示 ...

  3. Mac下的串口通信-ORSSerialPort

    ================================2015/11/05======================================= 最近在工作中遇到有关Mac下串口通信 ...

  4. lua 使用

    根据公司自身业务需要,总结常用到的lua语法 Lua中的string库 链接:http://www.jb51.net/article/57613.htm string.len(s)          ...

  5. 【android-tips】如何在view中取得activity对象

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 今天想实现在view中返回上一个activity的功能,想了半天.因为在虽然view是包含于一个activity ...

  6. linux 下安装tomcat

    1.把安装包放到 tomcat的目录, 2.然后  解压  tar -zxvf apache-tomcat-7.0.70.tar.gz    解压. 3.然后启动tomcat

  7. HDU 4803 Poor Warehouse Keeper

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4803 解题报告:有一个记录器,一共有两个按钮,还有两行屏幕显示,第一行的屏幕显示的是数目,第二行的屏幕 ...

  8. 两轮自平衡小车双闭环PID控制设计

                                                                                            两轮自平衡小车的研究意义 ...

  9. 寻找下一款Prisma APP:深度学习在图像处理中的应用探讨(阅读小结)

    原文链接:https://yq.aliyun.com/articles/61941?spm=5176.100239.bloglist.64.UPL8ec 某会议中的一篇演讲,主要讲述深度学习在图像领域 ...

  10. maven简单配置

    maven-3.3.9下载 Maven是一个项目管理和综合工具.Maven提供了开发人员构建一个完整的生命周期框架.开发团队可以自动完成项目的基础工具建设,Maven使用标准的目录结构和默认构建生命周 ...