【python】词法语法解析模块ply
官方手册: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的更多相关文章
- python命令行解析模块--argparse
python命令行解析模块--argparse 目录 简介 详解ArgumentParser方法 详解add_argument方法 参考文档: https://www.jianshu.com/p/aa ...
- 编译impala、拓展impala语法解析模块
以前也编译过,但是每次编译都忘记怎么做,然后都得重新找需要下载的文件. 编译文件:buildall.sh 如果想只编译前端可以这样运行: buildall.sh -fe_only 编译时会去S3下载一 ...
- python之参数解析模块argparse
2.7之后python不再对optparse模块进行扩展,python标准库推荐使用argparse模块对命令行进行解析. 简单入门 先来看个例子: argparse_test.py: import ...
- python argparse(参数解析模块)
这是一个参数解析,可以用它快捷的为你的程序生成参数相关功能 import argparse(导入程序参数模块) # 创建argparse对象,并将产品简要说明加入show = '程序说明' ===&g ...
- python optparse命令解析模块
来源:http://www.cnblogs.com/pping/p/3989098.html?utm_source=tuicool&utm_medium=referral 来源:http:// ...
- Python 命令行解析模块 —— argparse
argparse是python标准库里面用来处理命令行参数的库,基本使用步骤如下: 1.import argparse 导入模块 2.parser = argparse.ArgumentPars ...
- 【python基础语法】模块和包管理,文件的操作(第8天课堂笔记)
''' 模块和包管理 模块和包的定义: 模块:模块是一个Python文件,以.py结尾,包含了Python对象定义和Python语句 包:Python中的包就是一个包含__init__.py文件的目录 ...
- Python中配置文件解析模块-ConfigParser
Python中有ConfigParser类,可以很方便的从配置文件中读取数据(如DB的配置,路径的配置).配置文件的格式是: []包含的叫section, section 下有option=value ...
- python命令行参数解析模块argparse和docopt
http://blog.csdn.net/pipisorry/article/details/53046471 还有其他两个模块实现这一功能,getopt(等同于C语言中的getopt())和弃用的o ...
随机推荐
- jquery Ajax跨域调用WebServices方法
由于公司需要开发一个手机页面,想提供给同事直接在手机上可以查询SAP资料.数据需要使用js调用webserver来获取. 因为初次使用Jquery调用Webserver,所以期间并不顺利.测试调用We ...
- 增值税——基础知识
一.增值税的概念 增值税是对从事销售货物或者提供加工.修理修配劳务以及从事进出口货物的单位和个人取得的增值额为课税对象征收的一种税. 增值额是指纳税人在生产.经营或劳务活动中所创造的新增价值,即纳税人 ...
- R语言 小程序
x<-sample(1:11) x 日期和时间 ###Data and Time### > data_time <- data.frame(data = c("2015-0 ...
- R语言 推荐算法 recommenderlab包
recommend li_volleyball 2016年3月20日 library(recommenderlab) library(ggplot2) # data(MovieLense) dim(M ...
- HDOJ 4389 X mod f(x)
数位DP........ X mod f(x) Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/ ...
- 2015baidu复赛2 连接的管道(mst && 优先队列prim)
连接的管道 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- 【C语言入门教程】4.2 二维数组
C 语言允许使用多维数组,即使用多组小标的数组,二维数组是最常用的多维数组.多维数组在内存中存放数据的顺序与一维数组相同,使用连续的存储单元. 4.2.1 二维数组的一般形式 二维数组的一般声明形式为 ...
- mongodb安装 window
安装MongoDB 1.按照操作系统下载http://www.mongodb.org/downloads. 2.在D盘新建MongoDB文件夹(此文件夹为自定义的数据库安装目录D:\MongoDB)把 ...
- mysql:You can't specify target table 'bpm_tksign_data' for update in FROM clause
UPDATE bpm_tksign_data WHERE actinstid ' AND nodeid = 'SignTask1' AND batch = ( SELECT max(a.batch) ...
- 两款基于Jquery的图表插件
一.EasyPieChart 页面加载时,运行initPieChart()函数,调用easyPieChart()函数,显示出图表. 代码: var initPieChart = function() ...