首页 > 代码库 > 【python】词法语法解析模块ply
【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 requiredtokens = ( ‘NUMBER‘, ‘PLUS‘, ‘MINUS‘, ‘TIMES‘, ‘DIVIDE‘, ‘LPAREN‘, ‘RPAREN‘,)# Regular expression rules for simple tokenst_PLUS = r‘\+‘t_MINUS = r‘-‘t_TIMES = r‘\*‘t_DIVIDE = r‘/‘t_LPAREN = r‘\(‘t_RPAREN = r‘\)‘# A regular expression rule with some action codedef t_NUMBER(t): r‘\d+‘ t.value = int(t.value) return t# Define a rule so we can track line numbersdef t_newline(t): r‘\n+‘ t.lexer.lineno += len(t.value)# A string containing ignored characters (spaces and tabs)t_ignore = ‘ \t‘# Error handling ruledef t_error(t): print("Illegal character ‘%s‘" % t.value[0]) t.lexer.skip(1)# Build the lexerlexer = lex.lex()
注意:
里面名字的命名格式是固定的,ID的名称必须叫tokens,每个ID具体的内容必须用t_ID来指定。
单个字符可以直接定义变量,复杂成分要用函数形式表示,并且一定要有一个该成分的正则表达式字符串!
比如上面例子中,t_NUMBER函数中有一个r‘\d+‘,这在一般的python程序中看起来没有意义,但是在ply中则是必须的!它指定了模块如何划分NUMBER。
更多注意事项参考官方手册。
具体使用:
# Test it outdata = http://www.mamicode.com/‘‘‘3 + 4 * 10 + -20 *2‘‘‘# Give the lexer some inputlexer.input(data)# Tokenizewhile True: tok = lexer.token() if not tok: break # No more input print(tok)
结果:
$ python example.pyLexToken(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 | termterm : term * factor | term / factor | factorfactor : NUMBER | ( expression )
用ply实现四则运算语法分析:
# Yacc exampleimport ply.yacc as yacc# Get the token map from the lexer. This is required.from calclex import tokensdef 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 errorsdef p_error(p): print("Syntax error in input!")# Build the parserparser = 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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。