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 > 

這個例子同樣使用上面的方法來解讀就可以了。

發佈了19 篇原創文章 · 獲贊 12 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章