【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 ...
随机推荐
- [译]A Beginner’s Guide to npm — the Node Package Manager
原文: http://www.sitepoint.com/beginners-guide-node-package-manager/ Installing Node.js 验证你的安装是否成功. $ ...
- Java-Linux系统中搭建开发环境
准备工作: 0.虚拟机中的系统→{RHEL-I386} 1.JDK→{首先要知道下载哪个版本" [zf@string ~]$ getconf LONG_BIT ":".t ...
- solr多条件查询(一)
每个项目的数据结构可能不同,查询的格式有可能不同,本项目所有的字段为动态的,所以整理了一下, 1.查询所有字段中包含”测试“但是所有的TM不包含”江苏大学“ q:X_1457955996315KEY: ...
- SQL获取日期格式
) + ' ' + CONVERT(VARCHAR, DATEPART(hh, GetDate())) + ':' + ) AS Date ),) ),) ),) as DateTime) as [D ...
- GATK软件介绍
背景介绍 GATK全称是The Genome Analysis Toolkit,是Broad Institute(The Broad Institute, formerly the Broad Ins ...
- SGU 495. Kids and Prizes
水概率....SGU里难得的水题.... 495. Kids and Prizes Time limit per test: 0.5 second(s)Memory limit: 262144 kil ...
- 随鼠标移动tab
<script language="javascript"> function tabChange(obj, id) { var ...
- webpack 教程 那些事儿02-从零开始
接着上篇我们有了最简单的安装了webpack的项目目录这节我们从零开始搭建一个简单的基于webpack的spa应用demo本节只说基础常用配置项,复杂后续讲解. 文章目录 1. 新建项目结构目录,如下 ...
- String与InputStream互转的几种方法
[java] view plain copy /** * 利用BufferedReader实现Inputstream转换成String <功能详细描述> * * @param in * @ ...
- BZOJ 4579: [Usaco2016 Open]Closing the Farm
Description 依次删去一个点和它的边,问当前图是否连通. Sol 并查集. 倒着做就可以了. 每次将一个点及其的边加入,如果当前集合个数大于 1,那么就不连通. Code /******** ...