Ply tries to figure out a "starting rule" based on your rules. With what you have written, it will make "exp" the start rule, which says there is only one expression per string or file. If you want multiple expressions, you probably want a list of expressions:
def p_exp_list(p):
"""exp_list :
| exp_list exp
"""
if len(p) == 1:
p[0] = []
else:
p[0] = p[1] + [p[2]]
Then your starting rule will be "exp_list". This would allow multiple expressions on each line. If you want to limit to one expression per line, then how about:
def p_line_list(p):
"""line_list :
| line_list line
"""
if len(p) == 1:
p[0] == []
else:
p[0] = p[1] + [p[2]]
def p_line(p):
"""line : exp NL"""
p[0] = p[1]
I don't think you can use newline as a literal, (because it might mess up regular expressions). You probably need a more specific token rule:
t_NL = r'[\r*\n]'
Pretty sure this would work, but haven't tried it as there isn't enough to go on.
As for the "#token" line, you could just skip it, if it doesn't appear anywhere else:
def t_COMMENT(t):
r'#.*$'
pass # ignore this token