簡體   English   中英

如何使用 PLY 在解析器中實現循環依賴語法結構

[英]How to implement for circular dependency grammar structure in parser using PLY

作為家庭作業的一部分,我正在嘗試使用 PLY 構建掃描儀和解析器。

以下是我試圖實現的語法:

以下是我試圖實現的語法

我想我能夠處理掃描儀部分,但我需要解析器部分的幫助。 我正在努力在兩者中添加規則。 我不斷收到以下消息。 根據語法,就像某種循環引用。 在這種情況下,我不確定如何正確實施它。 我對編譯器概念以及 Python 編程相當陌生。 任何幫助深表感謝。

警告:1減少/減少沖突

警告:使用規則解決 state 3 中的減少/減少沖突(語句 -> binop)

警告:state 3 中的拒絕規則(術語 -> binop)

這是我的源代碼:

import sys
sys.path.insert(0, "../..")

tokens = ('ID',   # ID represents a variable name
          'NUM',  # NUM represents the signed integer data type
          'EQL',  # EQL represents the equal sign (=)
          'ADD',  # ADD represents the addition operator (+)
          'SUB',  # SUB represents the subtraction operator (-)
          'MUL',  # MUL represents the multiplication operator (*)
          'DIV',  # DIV represents the division operator (/)
          'EXP',  # EXP represents the exponentiation operator (**)
          'STR',  # STR represents the string data type
          'VAR'   # var represents the literal string 'VAR'
          )

# Regular expresssion rules for the equal sign and literals
t_EQL = r'\='
t_ADD = r'\+'
t_SUB = r'-'
t_MUL = r'\*'
t_DIV = r'\/'

# create a method for parsing VAR tokens
    # regex for finding VAR tokens
    # return token
def t_VAR(t):
  r'VAR'
  return t

# create a method for parsing ID tokens
    # regex for finding ID tokens
    # return token
def t_ID(t):
  r'[a-zA-Z_][0-9a-zA-Z_]*'
  return t

# create a method for parsing NUM tokens
    # regex for finding NUM tokens
    # convert token from str to int
    # return token
def t_NUM(t):
  r'-?\d+'
  t.value = int(t.value)
  return t

# create a method for parsing EXP tokens
    # regex for finding EXP tokens
    # return token
def t_EXP(t):
  r'\*{2}'
  return t

# create a method for parsing STR tokens
    # regex for finding STR tokens
    # return token
def t_STR(t):
  r'"[\s.a-zA-Z_]+"'
  return t

t_ignore = " \t"

def t_newline(t):
    r'\n+'
    t.lexer.lineno += t.value.count("\n")

def t_error(t):
    print("Illegal character '%s'" % t.value[0])
    t.lexer.skip(1)

# Build the lexer
import ply.lex as lex
lexer = lex.lex()


# Parsing rules

precedence = (
    ('left','ADD','SUB'),
    ('left','MUL','DIV'),
    ('left', 'EXP'),
    ('right', 'UMINUS')
    )

# dictionary of names
names = { }

def p_statement(p):
  '''statement : assign
               | declare
               | binop
               '''
  p[0] = p[1]

def p_statement_print(p):
  '''statement : term'''
  print(p[1])

def p_assign(p):
    '''assign : ID EQL term
              | ID EQL STR'''
    names[p[1]] = p[3]

def p_binop(p):
    '''binop : term ADD term
                  | term SUB term
                  | term MUL term
                  | term DIV term
                  | term EXP term
                  | STR ADD STR'''
    if p[2] == '+'  : p[0] = p[1] + p[3]
    elif p[2] == '-': p[0] = p[1] - p[3]
    elif p[2] == '*': p[0] = p[1] * p[3]
    elif p[2] == '/': p[0] = p[1] / p[3]
    elif p[2] == '**': p[0] = p[1] ** p[3]

def p_declare(p):
  '''declare : VAR ID
             | VAR assign'''
  names[p[0]] = p[2]

def p_uminus(p):
    'term : SUB term %prec UMINUS'
    p[0] = -p[2]

def p_term_binop(p):
  'term : binop'
  p[0] = p[1]


def p_term_number(p):
  'term : NUM'
  p[0] = p[1]

def p_term_name(p):
  'term : ID'
  try:
    p[0] = names[p[1]]
  except LookupError:
    print("Undefined name '%s'" % p[1])
    p[0] = 0

def p_error(p):
  print("Syntax error at '%s'" % p.value)

import ply.yacc as yacc
parser = yacc.yacc()

while True:
  try:
    s = input("Enter a line of code: ")
  except EOFError:
    break
  if not s:
    continue
  yacc.parse(s)

你有這三個規則:

statement : binop
statement : term
term : binop

這是模棱兩可的,因為由binop組成的語句可以直接解析為binop或作為binopterm (碰巧,這兩種情況下的操作不同,但即使操作相同,Ply 也會抱怨,因為 Ply 並沒有真正看到這些操作;它們是不透明的 Python 代碼。)

因此,您需要通過刪除其中一個模棱兩可的產品來解決這個問題。 原始語法應該指導你。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM