其他分享
首页 > 其他分享> > PLY的LALR语法详细解释

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