2015-04-20 6 views
1

Это долгий вопрос, надеюсь, вы, ребята, проявили терпение.Python - проверка синтаксиса молекулярных формул

Я пишу программу, которая проверяет правильность синтаксиса для молекулярной формулы.

У меня есть BNF-синтаксис:

<formel>::= <mol> \n 
<mol> ::= <group> | <group><mol> 
<group> ::= <atom> |<atom><num> | (<mol>) <num> 
<atom> ::= <LETTER> | <LETTER><letter> 
<LETTER>::= A | B | C | ... | Z 
<letter>::= a | b | c | ... | z 
<num> ::= 2 | 3 | 4 | ... 

и это мой код:

from linkedQFile import LinkedQ 
import string 
import sys 

ATOMER = ["H","He","Li","Be","B","C","N","O","F","Ne","Na","Mg","Al","Si","P","S","Cl","Ar"] 

class FormelError(Exception): 
    pass 
class Gruppfel(Exception): 
    pass 

q = LinkedQ() 
formel= "(Cl)2)3" 

for symbol in formel: 
    q.put(symbol) 


def readNum(): 
    """Reads digits larger than 1. Raises exception if condition is not fulfilled.""" 
    try: 
     if int(q.peek()) >= 2: 
      print(q.peek()) 
      q.get() 
      return 
     else: 
      q.get() 
      print("Too small digit at the end of row: "+getRest()) 
      sys.exit() 
    except (ValueError,TypeError): 
     raise FormelError("Not a number.") 

def readletter(): 
    """Reads lowercase letters and returns them.""" 
    if q.peek() in string.ascii_lowercase: 
     print(q.peek()) 
     return q.get() 
    else: 
     raise FormelError("Expected lowercase letter.") 

def readLetter(): 
    """Reads capital letters and returns them.""" 
    if q.peek() in string.ascii_uppercase: 
     print(q.peek()) 
     return q.get() 
    else: 
     raise FormelError("Expected capital letter.") 

def readAtom(): 
    """Reads atoms on the form X and Xx. Raises Exception if the format for an atom is not fulfilled or if the atom does not exist.""" 
    X = "" 
    try: 
     X += readLetter() 
    except FormelError: 
     print("Missing capital letter at end of row: "+getRest()) 
     sys.exit() 
     return 

    try: 
     x = readletter() 
     atom = X+x 
    except (FormelError, TypeError): 
     atom = X 

    if atom in ATOMER: 
     return 
    else: 
     raise FormelError("Unknown atom.") 

def readGroup(): 
    if q.peek() in string.ascii_uppercase or q.peek() in string.ascii_lowercase: 
     try: 
      readAtom() 
     except: 
      print("Unknown atom at end of row: "+getRest()) 
      sys.exit() 
     try: 
      while True: 
       readNum() 
     except FormelError: 
      pass 
     return 
    if q.peek() == "(": 
     print(q.peek()) 
     q.get() 
     try: 
      readMol() 
     except FormelError: 
      pass 
     if q.peek() == ")": 
      print(q.peek()) 
      q.get() 
     else: 
      print("Missing right parenthesis at end of row: "+ getRest()) 
      sys.exit() 
      return 
     digitfound = False 
     try: 
      while True: 
       readNum() 
       digitfound = True 
     except: 
      if digitfound: 
       return 
      print("Missing digit at end of row: "+getRest()) 
      sys.exit() 
      return 
    raise FormelError("Incorrect start of group") 

def readMol(): 
    try: 
     readGroup() 
    except FormelError: 
     print("Incorrect start of group at end of row: "+getRest()) 
     raise FormelError 
    if q.peek() == None: 
     return 
    if not q.peek() == ")": 
     try: 
      readMol() 
     except FormelError: 
      pass 

def readFormel(): 
    try: 
     readMol() 
    except: 
     return 
    print("Correct formula") 

def getRest(): 
    rest = "" 
    while not q.isEmpty(): 
     rest += q.get() 
    return rest 

readFormel() 

Теперь код должен принять некоторые приведенные формулы и предоставить код ошибки для некоторых приведены неверно формулы. Давайте посмотрим на этих приведенных формулах:

Правильно: Si (С3 (СООН) 2) 4 (H2O) 7

Неправильно: Н2О) Fe

(Cl) 2) 3

Программа принимает правильную формулу, но, к сожалению, и неправильные. Причина этого заключается в том, что если оператор в:

if not q.peek() == ")": 
    try: 
     readMol() 
    except FormelError: 
     pass 

делает это так, что круглые скобки несбалансированное вправо (с одним или несколькими скобка слишком много на правой стороне) проскользнуть через код, вместо того, чтобы быть обнаружены как неправильный запуск «группы». Как я могу это исправить, хотя Si (C3 (COOH) 2) 4 (H2O) 7 принимается как синтаксически правильная?

Спасибо за ваше терпение :)

+0

Если вы считаете, что мой ответ полезен, вы должны его перенести. –

ответ

1

Ваш код readMol имеет ошибочное испытание (вы даже сказали нам) для «)». Ваша грамматика не показывает необходимость такого теста, если вы кодируете (как есть) recursive descent parser.

В самом деле, вы грамматике имеет нечетное правило мол:

<mol> ::= <group> | <group><mol> 

Это не хорошо работать с рекурсивными спускаемых анализаторами. У вас есть рефакторинг таких правил для совместного использования общих префиксов в каждом правиле. В этом случае, это легко:

<mol> ::= <group> (<mol> | empty) ; 

Затем вы пишете код непосредственно из правила грамматики (см ссылку выше) [Вы вроде сделал это, за «)» проверка кроме.] Он должен искать что-то вроде этого (я не эксперт питона):

def readMol(): 
    try: 
     readGroup() 
    except FormelError: 
     print("Incorrect start of group at end of row: "+getRest()) 
     raise FormelError 
    try: 
     readMol() 
    except FormelError: 
     pass 

это полезно при написании рекурсивных парсеров, массировать грамматику в наиболее совместимую форму первой (как я сделал с мол правилом) , Тогда кодирование отдельных распознавателей является чисто механической задачей, которая трудно ошибиться.