0

I'm writing a syntax controller for empirical formulas. It seems to be working fairly well, but there is one error that I can not seem to fix.

Here is the code:

import string
from linkedQFile import LinkedQ

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

class Formelfel(Exception):
    pass

def readFormel():
    if q.peek() == None:
        print("Formel saknas. ")
    readMol()
    print("Formeln är syntaktiskt korrekt")
    #newline check?

def readMol():
    if q.peek() == None:
        return
    readGroup()
    readMol()
    return

def readGroup():
    if q.peek() == "(":
        print(q.get(), end="")
        if q.peek() in string.ascii_lowercase or q.peek() in string.ascii_uppercase:
            readMol()
        else:
            raise Formelfel
    if q.peek() == ")":
        print(q.get(), end="")
        readNum()
        return
    readAtom()
    try: 
        readNum()
    except Formelfel:
        pass
    return

def readAtom():
    X = readLetter()
    try:
        x = readletter() 
    except Formelfel:
        x = ""
    atom = X+x
    if atom in ATOMER:
        return
    rest=""
    while not q.isEmpty():
        rest += print(q.get(), end="")
    raise Formelfel("Okänd atom vid radslutet "+rest)

def readNum():
    try:
        if q.peek() != None:
            print(q.peek())
            while not q.peek() in string.ascii_uppercase and not q.peek() in string.ascii_lowercase and not q.peek() == "(" and not q.peek()==")": # If q.peek() is a number
                if q.peek() == None:
                    return
                int(q.get())    
        return
    except:
        raise Formelfel

def readLetter():
    if q.peek() in string.ascii_uppercase:
        x =q.get()
        print(x,end="")
        return x
    raise Formelfel

def readletter():
    if q.peek() == None:
        raise Formelfel
    if q.peek() in string.ascii_lowercase:
        x =q.get()
        print(x,end= "")
        return x
    raise Formelfel

formel= "Si(C3(COOH)2)4(H2O)7"
q = LinkedQ()
for symbol in formel:
    q.put(symbol)

readFormel()

I get the following output and error:

Si(
(C3
(CO
OO
OH
H)
)2
)4
(H2
O)
)7
Traceback (most recent call last):
  File "formelkoll.py", line 59, in readNum
    while not q.peek() in string.ascii_uppercase and not q.peek() in string.ascii_lowercase and not q.peek() == "(" and not q.peek()==")": # If q.peek() is a number
TypeError: 'in <string>' requires string as left operand, not NoneType

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "formelkoll.py", line 88, in <module>
    readFormel()
  File "formelkoll.py", line 12, in readFormel
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 19, in readMol
    readGroup()
  File "formelkoll.py", line 27, in readGroup
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 19, in readMol
    readGroup()
  File "formelkoll.py", line 27, in readGroup
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 19, in readMol
    readGroup()
  File "formelkoll.py", line 27, in readGroup
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 20, in readMol
    readMol()
  File "formelkoll.py", line 19, in readMol
    readGroup()
  File "formelkoll.py", line 32, in readGroup
    readNum()
  File "formelkoll.py", line 65, in readNum
    raise Formelfel
__main__.Formelfel

I don't understand why this error occurs, as I have an if statement:

if q.peek() != None:

before the row where the error occurs. In other words, why is None allowed to slip through this if statement?

Bhavesh Odedra
  • 10,990
  • 12
  • 33
  • 58
Sahand
  • 7,980
  • 23
  • 69
  • 137
  • 2
    After you call `q.get()`, the value returned by `q.peek()` will be different. – khelwood Apr 18 '15 at 08:51
  • 1
    Next time, by the way, try to reduce your bugs down to a SSCCE ("short, self-contained, correct example"; http://sscce.org/) or MVCE ("minimal, correct, verifiable example"; http://stackoverflow.com/help/mcve); adding more than the minimum amount of code needed to reproduce a bug makes it hard for other folks to help -- and the very process of reducing a bug to its minimal components is likely to help you solve the problem yourself. – Charles Duffy Apr 18 '15 at 16:34

1 Answers1

0

I figured it out. As a commenter said, q.get() is called, which changes the value of q.peek(). The switching of two rows solved the problem.

def readNum():
    try:
        if q.peek() != None: #Vrf får vi error NoneType trots detta??
            print(q.peek())
            while not q.peek() in string.ascii_uppercase and not q.peek() in string.ascii_lowercase and not q.peek() == "(" and not q.peek()==")": 
                int(q.get())    
                if q.peek() == None: 
                    return

        return
    except:
        raise Formelfel
Sahand
  • 7,980
  • 23
  • 69
  • 137
  • You will have a more readable code if you use in your while condition an auxiliary function that takes a 1-char string as argument and returns True or False... – Eric Levieil Apr 18 '15 at 09:02