PLY的LALR语法详细解释
作者:互联网
首先还是先给出本次可以运行的程序。
###################################################
tokens = ['ID', 'FLOAT', 'INT']
literals = ['=', '.', '<', '+', '-', '*', '/', '(', ')']
t_ignore = " "
#t_ID = r'[a-zA-Z_][a-zA-Z_0-9]*'
def t_ID(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
print('t_ID', t.value)
return t
def t_FLOAT(t):
r'\d+\.\d+'
t.value = float(t.value)
print('t_FLOAT', t.value)
return t
def t_INT(t):
r'\d+'
t.value = int(t.value)
print('t_INT', t.value)
return t
def t_newline(t):
r'\n+'
t.lexer.lineno += t.value.count("\n")
print('t_newline')
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
# Build the lexer
import ply.lex as lex
myLex = lex.lex()
###################################################
# dictionary of ids
ids = {}
# Parsing rules
precedence = (
('left', '+', '-'),
('left', '*', '/'),
('right', 'UMINUS'),
)
### statement ###
def p_statement_assign(p):
'statement : ID "=" expression'
ids[p[1]] = p[3]
for i in range(len(p)):
print('p_statement_assign', 'pos', i, 'value', p[i])
### statement ###
def p_statement_expr(p):
'statement : expression'
print(p[1])
for i in range(len(p)):
print('p_statement_expr', 'pos', i, 'value', p[i])
### expression ###
def p_expression_plus(p):
'''expression : expression '+' expression'''
p[0] = p[1] + p[3]
for i in range(len(p)):
print('p_expression_plus', 'pos', i, 'value', p[i])
### expression ###
def p_expression_minus(p):
'''expression : expression '-' expression'''
p[0] = p[1] - p[3]
for i in range(len(p)):
print('p_expression_minus', 'pos', i, 'value', p[i])
### expression ###
def p_expression_times(p):
'''expression : expression '*' expression'''
p[0] = p[1] * p[3]
for i in range(len(p)):
print('p_expression_times', 'pos', i, 'value', p[i])
### expression ###
def p_expression_div(p):
'''expression : expression '/' expression'''
p[0] = p[1] / p[3]
for i in range(len(p)):
print('p_expression_div', 'pos', i, 'value', p[i])
### expression ###
def p_expression_group(p):
"expression : '(' expression ')'"
p[0] = p[2]
for i in range(len(p)):
print('p_expression_group', 'pos', i, 'value', p[i])
### expression ###
def p_expression_float(p):
"expression : FLOAT"
p[0] = p[1]
for i in range(len(p)):
print('p_expression_float', 'pos', i, 'value', p[i])
### expression ###
def p_expression_int(p):
"expression : INT"
p[0] = p[1]
for i in range(len(p)):
print('p_expression_int', 'pos', i, 'value', p[i])
### expression ###
def p_expression_id(p):
"expression : ID"
try:
p[0] = ids[p[1]]
except LookupError:
print("Undefined name '%s'" % p[1])
p[0] = 0
for i in range(len(p)):
print('p_expression_id', 'pos', i, 'value', p[i])
### expression ###
def p_expression_uminus(p):
"expression : '-' expression %prec UMINUS"
p[0] = -p[2]
for i in range(len(p)):
print('p_expression_uminus', 'pos', i, 'value', p[i])
def p_error(p):
if p:
print("Syntax error at '%s'" % p.value)
else:
print("Syntax error at EOF")
###################################################
import ply.yacc as yacc
#yacc.yacc(myLex)
yacc.yacc()
while True:
try:
s = input('calc > ')
except EOFError:
break
if not s:
continue
yacc.parse(s)
print('ids', ids)
这段程序中,参考上次的解释:https://mp.csdn.net/postedit/104059437。
首先对其中解释不清楚的地方,做进一步的解释。
在ply.lex和ply.yacc中的都存在优先级的问题,在ply.lex中优先级是通过先后顺序决定的,
在ply.yacc中,优先级通过两个地方决定。
第一个地方:
precedence = (
('left', '+', '-'),
('left', '*', '/'),
('right', 'UMINUS'),
)
在这里决定了优先级,越靠后的优先级越高,还有另外一个地方,
### expression ###
def p_expression_uminus(p):
"expression : '-' expression %prec UMINUS"
p[0] = -p[2]
for i in range(len(p)):
print('p_expression_uminus', 'pos', i, 'value', p[i])
在这一段程序中的,"expression : '-' expression %prec UMINUS",中的,%prec UMINUS,为负数指定了,UMINUS,优先级。
在执行上面的程序之后,会生成一个parser.out和parsetab.py两个文件,首先先来说说parser.out文件。
打开parser.out首先看到的是解析的规则:
Grammar
Rule 0 S' -> statement
Rule 1 statement -> ID = expression
Rule 2 statement -> expression
Rule 3 expression -> expression + expression
Rule 4 expression -> expression - expression
Rule 5 expression -> expression * expression
Rule 6 expression -> expression / expression
Rule 7 expression -> ( expression )
Rule 8 expression -> FLOAT
Rule 9 expression -> INT
Rule 10 expression -> ID
Rule 11 expression -> - expression
咱们通过执行几个例子,分别来看输出:
第一个例子:
calc > 1
t_INT 1
p_expression_int pos 0 value 1
p_expression_int pos 1 value 1
1
p_statement_expr pos 0 value None
p_statement_expr pos 1 value 1
ids {}
calc >
输入字符串,1,的时候,首先ply.lex将字符串转换成token,
t_INT 1
之后,ply.yacc识别到了,Rule 9 expression -> INT,将INT数字归约为了expression
p_expression_int pos 0 value 1
p_expression_int pos 1 value 1
之后,ply.yacc识别到了,Rule 2 statement -> expression,将statement归约为了statement
1
p_statement_expr pos 0 value None
p_statement_expr pos 1 value 1
第二个例子:
calc > a = 1
t_ID a
t_INT 1
p_expression_int pos 0 value 1
p_expression_int pos 1 value 1
p_statement_assign pos 0 value None
p_statement_assign pos 1 value a
p_statement_assign pos 2 value =
p_statement_assign pos 3 value 1
ids {'a': 1}
calc >
输入字符串,a=1,首先ply.lex将字符串转换成token,
t_ID a
t_INT 1
之后,ply.yacc识别到了,Rule 9 expression -> INT,将INT数字归约为了expression
p_expression_int pos 0 value 1
p_expression_int pos 1 value 1
之后,ply.yacc识别到了,Rule 1 statement -> ID = expression,将expression存储到变量ID中
p_statement_assign pos 0 value None
p_statement_assign pos 1 value a
p_statement_assign pos 2 value =
p_statement_assign pos 3 value 1
第三个例子:
calc > a = 1+2-3
t_ID a
t_INT 1
p_expression_int pos 0 value 1
p_expression_int pos 1 value 1
t_INT 2
p_expression_int pos 0 value 2
p_expression_int pos 1 value 2
p_expression_plus pos 0 value 3
p_expression_plus pos 1 value 1
p_expression_plus pos 2 value +
p_expression_plus pos 3 value 2
t_INT 3
p_expression_int pos 0 value 3
p_expression_int pos 1 value 3
p_expression_minus pos 0 value 0
p_expression_minus pos 1 value 3
p_expression_minus pos 2 value -
p_expression_minus pos 3 value 3
p_statement_assign pos 0 value None
p_statement_assign pos 1 value a
p_statement_assign pos 2 value =
p_statement_assign pos 3 value 0
ids {'a': 0}
calc >
输入字符串,a=1+2-3,首先ply.lex将字符串转换成token,由于是便解释便执行,所以一开始只扫描到了
t_ID a
t_INT 1
之后,ply.yacc识别到了,Rule 9 expression -> INT,将INT数字归约为了expression
p_expression_int pos 0 value 1
p_expression_int pos 1 value 1
之后,ply.lex扫描到了
t_INT 2
之后,ply.yacc识别到了,Rule 9 expression -> INT,将INT数字归约为了expression
p_expression_int pos 0 value 2
p_expression_int pos 1 value 2
由于加法是,左结合,优先级较低,所以根据,Rule 3 expression -> expression + expression,进行归约
p_expression_plus pos 0 value 3
p_expression_plus pos 1 value 1
p_expression_plus pos 2 value +
p_expression_plus pos 3 value 2
之后,ply.lex扫描到了
t_INT 3
之后,ply.yacc识别到了,Rule 9 expression -> INT,将INT数字归约为了expression
p_expression_int pos 0 value 3
p_expression_int pos 1 value 3
由于减法是,左结合,优先级较低,所以根据,Rule 4 expression -> expression - expression,进行归约
p_expression_minus pos 0 value 0
p_expression_minus pos 1 value 3
p_expression_minus pos 2 value -
p_expression_minus pos 3 value 3
之后,ply.yacc识别到了,Rule 1 statement -> ID = expression,将expression存储到变量ID中
p_statement_assign pos 0 value None
p_statement_assign pos 1 value a
p_statement_assign pos 2 value =
p_statement_assign pos 3 value 0
第四个例子:
calc > a = 1+2*(3-4/5)
t_ID a
t_INT 1
p_expression_int pos 0 value 1
p_expression_int pos 1 value 1
t_INT 2
p_expression_int pos 0 value 2
p_expression_int pos 1 value 2
t_INT 3
p_expression_int pos 0 value 3
p_expression_int pos 1 value 3
t_INT 4
p_expression_int pos 0 value 4
p_expression_int pos 1 value 4
t_INT 5
p_expression_int pos 0 value 5
p_expression_int pos 1 value 5
p_expression_div pos 0 value 0.8
p_expression_div pos 1 value 4
p_expression_div pos 2 value /
p_expression_div pos 3 value 5
p_expression_minus pos 0 value 2.2
p_expression_minus pos 1 value 3
p_expression_minus pos 2 value -
p_expression_minus pos 3 value 0.8
p_expression_group pos 0 value 2.2
p_expression_group pos 1 value (
p_expression_group pos 2 value 2.2
p_expression_group pos 3 value )
p_expression_times pos 0 value 4.4
p_expression_times pos 1 value 2
p_expression_times pos 2 value *
p_expression_times pos 3 value 2.2
p_expression_plus pos 0 value 5.4
p_expression_plus pos 1 value 1
p_expression_plus pos 2 value +
p_expression_plus pos 3 value 4.4
p_statement_assign pos 0 value None
p_statement_assign pos 1 value a
p_statement_assign pos 2 value =
p_statement_assign pos 3 value 5.4
ids {'a': 5.4}
calc >
这个例子同样使用上面的方法来解读就可以了。
夏特曼-S 发布了16 篇原创文章 · 获赞 7 · 访问量 3万+ 私信 关注标签:int,pos,value,语法,INT,PLY,statement,expression,LALR 来源: https://blog.csdn.net/shixiongtao/article/details/104071621