Is pyparsing really a recursive descent parser?

  • Thread starter Just Another Victim of the Ambient Morality
  • Start date
N

Neil Cerutti

I think I've just discovered a major hurdle in my understand of the
problem.
You keep saying "with backtracking." Why? Isn't "backtracking"
inherent in recursion? So, why can't these alleged "recursive descent
parsers" find valid parsings? How are they not already backtracking? What
was the point of being recursive if not to take advantage of the inherent
backtracking in it?
Obviously, these parsers aren't recursing through what I think they
should be recursing. The question is "why not?"

There are different kinds of recursion. Compare:

def fac1(x, y=1):
""" Compute factorials with a recursive function (it calls
itself), but the stack is not actually used for storing
anything important, i.e., it is tail-recursive. """
if x < 0:
raise ValueError('non-negative integer')
elif x == 0:
return y
else:
return fac1(x-1, y*x)

to

def fac2(x):
""" Computes factorials with a recursive process, keeping
the state of the calculation on the stack. """
if x < 0:
raise ValueError('non-negative integer')
if x == 0:
return 1
else:
return fac2(x-1) * x

to

def Ack(x, y):
""" The Ackermann function. Creates a humongous mess even
with quite tiny numbers. """
if x < 0 or y < 0:
raise ValueError('non-negative integer')
elif x == 0:
return y + 1
elif y == 0:
return foo3(x-1, 1)
else:
return foo3(x-1, foo3(x, y-1))

There's probably a word for the type of recursive process built
by fac2; the RDP's I'm most familiar with create a fac2 sort of
process, which stores valuable info on the stack.

And even though fac1 defines an iterative process, the code
itself is recursive, and you can call it a recursive function if
you wish (and in Python you might as well).
Correct me if I'm wrong but I'm beginning to think that
pyparsing doesn't typically use recursion, at all. It only
employs it if you create one, using the Forward class.
Otherwise, it does everything iteratively, hence the lack of
"backtracking."

It's recursive because each production rule calls other
production rules to define itself. A rule regularly ends up
calling itself. Consider the Parser class I built earlier.
list_tail keeps calling itself to continue consuming characters
in an ab_list. The stack is used to keep track of where we are in
the grammar; at any time you can look up the stack and see how
you got where you are--you 'descend' down from the topmost
productions to the most primitive productions, and then back up
once everything has been sorted out. Take another look
at the exception raised in my Parsing class example for an
illustrative traceback.
Finally, I can't believe you complain about potential speed
problems. First, depending on the size of the string, it's
likely to be the difference between 2ms and 200ms. Secondly,
if speed were an issue, you wouldn't go with a recursive
descent parser. You'd go with LALR or the many other parsing
techniques available. Recursive descent parsing is for those
situations where you need correctness, regardless of execution
time. These situations happen...

RDP is plenty fast; speed has never been one of it's
disadvantages, as far as I know. Today there are many
excellent parser generators and compiler builders that compose an
RDP under the hood, e.g., Antlr and Gentle.
I've said this before, albeit for a different language, but
it applies to Python just as well. I don't use Python to write
fast code, I use it to write code fast.
If _you_ "don't like to compromise speed for implementation
simplicity" then you have a plethora choices available to you.
What about the guy who needs to parse correctly and is
unconcerned about speed?

You have to be concerned about speed when something runs so
slowly in common circumstances compared to other well-known
algotithms that you can't practically wait for an answer. Would
you consider bubble-sort a suitable general-purpose sorting
algorithm for Python?
 
N

Neil Cerutti

def Ack(x, y):
""" The Ackermann function. Creates a humongous mess even
with quite tiny numbers. """
if x < 0 or y < 0:
raise ValueError('non-negative integer')
elif x == 0:
return y + 1
elif y == 0:
return foo3(x-1, 1)
else:
return foo3(x-1, foo3(x, y-1))

Urk! Of course those foo3 calls should have been Ack calls.
 
J

Just Another Victim of the Ambient Morality

Neil Cerutti said:
There are different kinds of recursion. Compare:

def fac1(x, y=1):
""" Compute factorials with a recursive function (it calls
itself), but the stack is not actually used for storing
anything important, i.e., it is tail-recursive. """
if x < 0:
raise ValueError('non-negative integer')
elif x == 0:
return y
else:
return fac1(x-1, y*x)

to

def fac2(x):
""" Computes factorials with a recursive process, keeping
the state of the calculation on the stack. """
if x < 0:
raise ValueError('non-negative integer')
if x == 0:
return 1
else:
return fac2(x-1) * x

to

def Ack(x, y):
""" The Ackermann function. Creates a humongous mess even
with quite tiny numbers. """
if x < 0 or y < 0:
raise ValueError('non-negative integer')
elif x == 0:
return y + 1
elif y == 0:
return foo3(x-1, 1)
else:
return foo3(x-1, foo3(x, y-1))

There's probably a word for the type of recursive process built
by fac2; the RDP's I'm most familiar with create a fac2 sort of
process, which stores valuable info on the stack.

And even though fac1 defines an iterative process, the code
itself is recursive, and you can call it a recursive function if
you wish (and in Python you might as well).

While interesting, none of this actually addresses the point I was
making. I wasn't saying that there was no recursion (at least, not in this
paragraph), I was saying that it wasn't recursing through what I thought it
should be recursing through. It recurses through a set of rules without any
regard to how these rules interact with each other. That's why it fails to
parse valid strings. In my opinion, it should recurse through appropriate
combinations of rules to determine validity, rather than by arbitrary
categorization...

It's recursive because each production rule calls other
production rules to define itself. A rule regularly ends up
calling itself. Consider the Parser class I built earlier.
list_tail keeps calling itself to continue consuming characters
in an ab_list. The stack is used to keep track of where we are in
the grammar; at any time you can look up the stack and see how
you got where you are--you 'descend' down from the topmost
productions to the most primitive productions, and then back up
once everything has been sorted out. Take another look
at the exception raised in my Parsing class example for an
illustrative traceback.

I guess that all the And and Or class in pyparsing call methods of each
other from each other, even if they are doing so from different
instantiations. I still say they're not recursing through the right
things...

RDP is plenty fast; speed has never been one of it's
disadvantages, as far as I know. Today there are many
excellent parser generators and compiler builders that compose an
RDP under the hood, e.g., Antlr and Gentle.

I think I read somewhere that LALR was O(n) while RDP was O(e^n). Most
people would consider that, at least, slower...
I think your examples may exemplify how little speed matters rather than
how fast RDPs are...

You have to be concerned about speed when something runs so
slowly in common circumstances compared to other well-known
algotithms that you can't practically wait for an answer. Would
you consider bubble-sort a suitable general-purpose sorting
algorithm for Python?

What you've stated is an hypothetical. You need to be concerned about
speed when "you can't practically wait for an answer." Encryption is based
on this, for example. I'm not sure what you're getting at with "compared to
other well known algorithms." Generally, the Python virtual machine is
pitifully slow when compared to a compiled C program, however, the
comparison is unnecessary. For most tasks, Python is plenty fast. Context
is key. Things don't have to be fast, they just need to be fast enough...
As I have said before, if you need speed, there are many options.
Often, speed is not important, especially with the power of computing
available today. Development time is increasingly valuable. So, for us who
are not overly concerned with speed, what are our options?
Now, if my RDP takes two minutes to parse four characters of text, I'd
sympathize with your point of view. However, it really isn't noticeably
slow. I may be nervous parsing an entire text file with it but I'd feel
safe parsing individual lines of a .conf file, for instance...
And I'll have you know that when I was still learning to program (that
is, before I knew sort() was part of the C standard), I would routinely
implement bubble sort 'cause it was so trivial to implement. I wouldn't
even short cut, necessarily. Just iterate it as many times as there are
elements in the list!
Also, it should probably be noted that bubble sort is very fast for
nearly sorted lists; much faster than quicksort. So, while it shouldn't be
the default sorting algorithm, you could have it somewhere in the library...
 
K

Kay Schluehr

I think I've just discovered a major hurdle in my understand of the
problem.
You keep saying "with backtracking." Why? Isn't "backtracking"
inherent in recursion? So, why can't these alleged "recursive descent
parsers" find valid parsings? How are they not already backtracking? What
was the point of being recursive if not to take advantage of the inherent
backtracking in it?
Obviously, these parsers aren't recursing through what I think they
should be recursing. The question is "why not?"

Backtracking and RD parsers are two different issues. An RD parser
keeps a grammar which is structured tree-like. So one feeds a start
symbol into the parser and the parser tries to "derive" a symbol of
the input stream by descending down along the tree of non-terminals.
For each non-terminal the parser calls itself because it is
essentially a recursive datastructure it iterates through.

Backtracking comes into play when the grammar is not properly "left
factored". This doesn't necessrily mean it is ambigous. Take for
example the following grammar:

S: A A 'foo' | A A 'bar'

The parser cannot immediately decide whether to take the left or the
right branch of the RHS. So it will checkout the left branch and when
it fails to derive 'foo' in the input stream it tries to select the
right branch. But the grammar is *not* ambigous: there is always a
unique parse tree that can be derived ( or none ).

Parser theory is mostly concerned with finding strategies to avoid
backtracking ( and resolving ambiguities ) because it slows parsers
down. One always wants to have parser effort that depends linear on
the size of the input stream.

This attitude is all too prevalent among computer professionals... Of
course it's a useful thing to shield users from the intricacies of parser
theory!

Yes, but people who develop parser generators shall no at least a bit
about it ;)
Just as much as it is useful to shield drivers from needing
automotive engineering or software users from programing. How many people
have come to this newsgroup asking about anomalous pyparsing behaviour,
despite their grammars being mathematically correct.
Think of it this way. You can force all the clients of pyparsing to
duplicate work on figuring out how to massage pyparsing to their grammars,
or you can do the work of getting pyparsing to solve people's problems,
once. That's what a library is supposed to do...
Finally, I can't believe you complain about potential speed problems.
First, depending on the size of the string, it's likely to be the difference
between 2ms and 200ms. Secondly, if speed were an issue, you wouldn't go
with a recursive descent parser.

ANTLR is recursive descendend, so are ratpack parsers. Python uses an
extremely optimized recursive descendend table based parser for
parsing the language. The parser flies and it is not LALR. Grammars
are more accessible in EBNF style and simpler to write so many people
( like me ) prefer RD parsers and seek for ways to optimize them. As
always there is a separation of concerns. The software engineering
aspects of modularization, interface abstraction, library / framework
implementation and the algorithmic aspects. I'd like to see both being
addressed by a parser generator architecture.
 
N

Neil Cerutti

While interesting, none of this actually addresses the
point I was making. I wasn't saying that there was no
recursion (at least, not in this paragraph), I was saying that
it wasn't recursing through what I thought it should be
recursing through. It recurses through a set of rules without
any regard to how these rules interact with each other. That's
why it fails to parse valid strings. In my opinion, it should
recurse through appropriate combinations of rules to determine
validity, rather than by arbitrary
categorization...

OK. I thought you were saying that, without backtracking there's
no recursion. Never mind!
I guess that all the And and Or class in pyparsing call
methods of each other from each other, even if they are doing
so from different instantiations. I still say they're not
recursing through the right things...

Backtracking seems orthoganal to recursion, to me.
I think I read somewhere that LALR was O(n) while RDP was
O(e^n). Most people would consider that, at least, slower...

To my knowledge, most RDPs are LL(1), which is O(n). As you
increase the amount of lookahead (a backtracking RDP is, I
suppose, be a brute-force way of getting infinite lookahead), the
complexity increases.
I think your examples may exemplify how little speed
matters rather than how fast RDPs are...

Also, it should probably be noted that bubble sort is very
fast for nearly sorted lists; much faster than quicksort. So,
while it shouldn't be the default sorting algorithm, you could
have it somewhere in the library...

Yes, bubble-sort runs fast in certain circumstances; you wouldn't
want to be bereft of it completely. Backtracking parsers do
probably have their place in the pantheon. I don't want
PyParsing to do backtracking by default, though it might be a
useful option.
 
N

Neil Cerutti

This attitude is all too prevalent among computer
professionals... Of course it's a useful thing to shield users
from the intricacies of parser theory! Just as much as it is
useful to shield drivers from needing automotive engineering or
software users from programing. How many people have come to
this newsgroup asking about anomalous pyparsing behaviour,
despite their grammars being mathematically correct.

You might be interested in the Early parsing algorithm. It is
more efficient than the naive approach used in your prototype,
and still handles ambiguous grammars.

There is a Python module SPARK that provides generic classes for
building small language compilers using an Early parser, and I
was able to get it to parse your ambiguous grammar without
trouble. It is not as convenient or as well documented as
PyParsing, but the parsing algorithm provides the power you're
looking for. It might serve as a backend for the library you're
currently working on.

http://www.cpsc.ucalgary.ca/~aycock/spark/
 
A

asdfjehqwjerhqjwljekrh

Well I'll be darned! All this time, I thought "recursive descent"
described the recursive behavior of the parser, which pyparsing
definitely has. I never knew that backing up in the face of parse
mismatches was a required part of the picture.

I looked at pyparsing about a year ago for some project and realized
that it wouldn't quite do what I needed it to. Maddeningly enough, I
cannot remember exactly what the problem was, but I think that it was
some combination of lack of backtracking and insufficient control over
whitespace skipping.

Mostly off-topic, what I could *really* use is something like this
folded into the Python standard library. I cannot count the number of
times that this would have saved me 30 lines of code.

http://mail.python.org/pipermail/python-dev/2004-August/047042.html

Mike
 
J

Just Another Victim of the Ambient Morality

Neil Cerutti said:
You might be interested in the Early parsing algorithm. It is
more efficient than the naive approach used in your prototype,
and still handles ambiguous grammars.

I think I might be interested in this algorithm, thank you!

There is a Python module SPARK that provides generic classes for
building small language compilers using an Early parser, and I
was able to get it to parse your ambiguous grammar without
trouble. It is not as convenient or as well documented as
PyParsing, but the parsing algorithm provides the power you're
looking for. It might serve as a backend for the library you're
currently working on.

http://www.cpsc.ucalgary.ca/~aycock/spark/

You know, I tried this thing but, for the life of me, I can't figure out
how to use it and the few tutorials out there are less than illuminating...
 
N

Neil Cerutti

I'll take this opportunity to correct my misspelling. It's
"Earley".
I think I might be interested in this algorithm, thank you!


You know, I tried this thing but, for the life of me, I
can't figure out how to use it and the few tutorials out there
are less than illuminating...

I'll send you the code I composed.

The tricky part of Spark is the Token and AST classes you have to
use. A type used as a token class is required to provide a
__cmp__ function that behaves in the following confounding
manner:

class Token(object):
def __cmp__(self, o):
return cmp(self.type, o)

If you attempt to use a list, string or a tuple as token, it just
barfs. AST's are required to provide an even weirder interface.

In effect, you have to write badly designed wrappers around
tuples and lists, respectively to take advantage of the generic
classes.

Go to the examples directory of the distribution to find working
versions of these stupid classes.

Once you get over that hurdle it becomes easier. Be sure to
provide your Parser and Scanner classes with an error method to
prevent the library from raising SystemExit(!) on errors. Scanner
classes are also required to override the t_default method to
prevent this mishap.

In short, it hasn't really evovled into a user-friendly package
yet.
 
J

Just Another Victim of the Ambient Morality

Neil Cerutti said:
I'll take this opportunity to correct my misspelling. It's
"Earley".


I'll send you the code I composed.

The tricky part of Spark is the Token and AST classes you have to
use. A type used as a token class is required to provide a
__cmp__ function that behaves in the following confounding
manner:

class Token(object):
def __cmp__(self, o):
return cmp(self.type, o)

If you attempt to use a list, string or a tuple as token, it just
barfs. AST's are required to provide an even weirder interface.

In effect, you have to write badly designed wrappers around
tuples and lists, respectively to take advantage of the generic
classes.

Go to the examples directory of the distribution to find working
versions of these stupid classes.

Once you get over that hurdle it becomes easier. Be sure to
provide your Parser and Scanner classes with an error method to
prevent the library from raising SystemExit(!) on errors. Scanner
classes are also required to override the t_default method to
prevent this mishap.

In short, it hasn't really evovled into a user-friendly package
yet.

Thank you.
How is it that I seem to be the only one in the market for a correct
parser? Earley has a runtine of O(n^3) in the worst case and O(n^2)
typically. I have trouble believing that everyone else in the world has
such intense run-time requirements that they're willing to forego
correctness. Why can't I find a pyparsing-esque library with this
implementation? I'm tempted to roll my own except that it's a fairly
complicated algorithm and I don't really understand how it's any more
efficient than the naive approach...
 
C

Chris Mellon

Thank you.
How is it that I seem to be the only one in the market for a correct
parser? Earley has a runtine of O(n^3) in the worst case and O(n^2)
typically. I have trouble believing that everyone else in the world has
such intense run-time requirements that they're willing to forego
correctness. Why can't I find a pyparsing-esque library with this
implementation? I'm tempted to roll my own except that it's a fairly
complicated algorithm and I don't really understand how it's any more
efficient than the naive approach...

You have an unusual definition of correctness. Many people would say
that an ambiguous grammar is a bug, not something to support.

In fact, I often use pyparsing precisely in order to disambiguate
(according to specific rules, which are embodied by the parser)
ambiguous input, like bizarre hand-entered datetime value.
 
S

Steven D'Aprano

Why can't I find a pyparsing-esque library with this implementation?
I'm tempted to roll my own except that it's a fairly complicated
algorithm and I don't really understand how it's any more efficient than
the naive approach...

I think you may have just answered your own question :)
 
J

Just Another Victim of the Ambient Morality

Chris Mellon said:
You have an unusual definition of correctness. Many people would say
that an ambiguous grammar is a bug, not something to support.

I don't think I do. Besides, you assume too much...
First off, we've already established that there are unambiguous grammars
for which pyparsing will fail to parse. One might consider that a bug in
pyparsing...
Secondly, I get the impression you want to consider ambiguous grammars,
in some sense, "wrong." They are not. Even if they were, if you are
parsing something for which you are not the creator and that something
employs an ambiguous grammar, what choice do you have? Furthermore, given a
set of possible parsings, you might be able to decide which one you favour
given the context of what was parsed! There's a plethora of applications
for parsing ambiguous grammars yet there are no tools for doing so?

In fact, I often use pyparsing precisely in order to disambiguate
(according to specific rules, which are embodied by the parser)
ambiguous input, like bizarre hand-entered datetime value.

What do you mean? How do you use pyparsing to disambiguate:


01-01-08


...?
 
J

Just Another Victim of the Ambient Morality

Steven D'Aprano said:
I think you may have just answered your own question :)

Yes, but my own answer lacks detail that I was hoping you could
provide...
 
C

Chris Mellon

I don't think I do.

There are an enormous variety of parsing tools, and it's the subject
of much research. And in all those tools, not one meets your
definition of correctness? You don't think that might make it unusual?

Besides, you assume too much...
First off, we've already established that there are unambiguous grammars
for which pyparsing will fail to parse. One might consider that a bug in
pyparsing...

You might. Or you might not, since it's well known that there are lots
of types of parsers that can't parse all possible grammars, but that
doesn't make those parsers useless.

Secondly, I get the impression you want to consider ambiguous grammars,
in some sense, "wrong." They are not.

Sure they are, at least in many contexts. I understand that you want
support for them, but it's by far more common to want one and only one
set of results from parsing a particular document.
Even if they were, if you are
parsing something for which you are not the creator and that something
employs an ambiguous grammar, what choice do you have?

You either disambiguate, or you don't accept ambiguous input. The
third option seems to be what you want, which is to find all possible
solutions and return all of them (and wouldn't this be NP-hard in the
general case?) but that's not a satisfactory result in most
applications.
Furthermore, given a
set of possible parsings, you might be able to decide which one you favour
given the context of what was parsed! There's a plethora of applications
for parsing ambiguous grammars yet there are no tools for doing so?

If you can do this, isn't this really a sign that your grammar is
context sensitive?
What do you mean? How do you use pyparsing to disambiguate:


01-01-08

The same way a human would - given an ambiguous date such as this, I
(arbitrarily) decided what it would mean. The alternative is to refuse
the input.
 
J

Just Another Victim of the Ambient Morality

Chris Mellon said:
There are an enormous variety of parsing tools, and it's the subject
of much research. And in all those tools, not one meets your
definition of correctness? You don't think that might make it unusual?

It doesn't appear to be common, I'll grant you that!
However, there is some research. For instance, the Earley parser
appears to be what I want (in conjunction with a parse tree builder). A CYK
parser would probably do, too. The algorithms are out there yet no one has
chosen to use any of them. At the same time, there are several LALR
parsers. Why did anyone need to write the second one after the first one
was written?!
In fact, in a sense, my problem is solved. There exists a solution to
my problem. It's just that no one has implemented that solution. I guess
you're right in that it really does appear to be an unusual problem but I
don't understand how...

You might. Or you might not, since it's well known that there are lots
of types of parsers that can't parse all possible grammars, but that
doesn't make those parsers useless.

No one said they were useless. I only said that a correct parser is
useful. Many people in this thread seem to disagree and I find this
incredible...

Sure they are, at least in many contexts. I understand that you want
support for them, but it's by far more common to want one and only one
set of results from parsing a particular document.

Okay, in some contexts, an ambiguous grammar may be considered
erroneous. However, in many other contexts, it's merely a fact of life.
How is it that there are no tools to address this? If nothing else,
pyparsing throws the same error it does when there is no valid parsing of
the string. Having no solution and having several solutions are not the
same thing...

You either disambiguate, or you don't accept ambiguous input. The
third option seems to be what you want, which is to find all possible
solutions and return all of them (and wouldn't this be NP-hard in the
general case?) but that's not a satisfactory result in most
applications.

What do you mean by "disambiguate?" Do you mean disambiguate the
grammar? One of the conditions of the problem is that you have no control
over the grammar, so that's really not an option. Also, an implicit
condition of solving a problem is that the problem be... solved, so not
accepting the input is not an option, either.
While there are many applications that can't deal with multiple
solutions, surely there are some? Again, perhaps you can pick one solution
over the other through the context of the parse results? That's kind of
hard to do if your parser refuses to return any results...
Just because a grammar is ambiguous doesn't mean the input string is.
It can easily be the case that most or all the input you're expecting will,
in practice, only produce one correct parse tree. In this case, it would be
useful for your parser to return a correct solution, even at random!
Finally, who cares if something is NP-Hard? Okay, in some situations,
you'd care. In many others, you don't. For instance, suppose your input
length has an upper bound? Unless that's a really high bound or a really
complex grammar, its runtime is not likely relevant...

If you can do this, isn't this really a sign that your grammar is
context sensitive?

I don't think so. I'm using the word "context" colloquially, not
grammatically. If you know what kind of output you're expecting and only
one of several parsings produces that kind of output, then you know which
one to run with. That doesn't mean the grammar is context sensitive; just
that the data is...
As an aside, do you know what tools are available for parsing context
senstive grammars?

The same way a human would - given an ambiguous date such as this, I
(arbitrarily) decided what it would mean. The alternative is to refuse
the input.

You use pyparsing to "arbitrarily decide what it would mean?"
You said you "often use pyparsing" to "disambiguate ambiguous input" and
I was wondering what you meant by this.
On one hand, it's not exactly a fair question since that date string is
not grammatically ambiguous. On the other hand, you're the one who brought
up "bizarre hand-entered datetime value," and I was only trying to give an
example of what you meant. So, what do you mean?
 
K

Kay Schluehr

What do you mean by "disambiguate?" Do you mean disambiguate the
grammar? One of the conditions of the problem is that you have no control
over the grammar, so that's really not an option. Also, an implicit
condition of solving a problem is that the problem be... solved, so not
accepting the input is not an option, either.

Could you please learn some parser theory 101 and then come back when
you have complaints about one or the other implemententation of a
particular Python parser? When some guy enters a forum with a "newbie
question" most of the time people are willing to give a fair and
comprehensive answer but they don't want to mess around with him
endlessly when he is not willing to learn and to listen.
 
J

JimJJewett

grammar << ((word + grammar) | (word + Literal(end)))
which works.

[Clarifies that the common (and similar) solution doesn't work -- this
works only because the literal binds tightly to the word, so you can't
get a word that matches on its own.]

Unfortunately, when the OneOrMore gets constructed, it does not have
any visibility beyond knowing what is to be repeated. Again, here is
the data structure that is being built:

- And
- OneOrMore
- Word(alphas)
- Literal('end')

Only at the level of the And is there any awareness that the OneOrMore
is followed by anything, let alone by something which could be
misinterpreted as something matching the OneOrMore's repetition
expression.
Can you suggest a way I could generalize this, so that OneOrMore stops
matching before it gets to 'end'?

Not efficiently.

I think JAVotAM's point was that you could make it at least an option
if OneOrMore (and ZeroOrMore ...) could return fallback results as
well.

Then, when the And failed, it could retry with the next fallback
result from OneOrMore before it gives up completely.

-jJ
 
D

[david]

Kay said:
Could you please learn some parser theory 101 and then come back when
you have complaints about one or the other implemententation of a
particular Python parser? When some guy enters a forum with a "newbie
question" most of the time people are willing to give a fair and
comprehensive answer but they don't want to mess around with him
endlessly when he is not willing to learn and to listen.
Immaturity is a mark of this group, isn't it? When all else fails,
resort to insults.

My suggestion is, if you can't be polite, just go back to your own room.

(david)
 
K

Kay Schluehr

Immaturity is a mark of this group, isn't it? When all else fails,
resort to insults.

Dear [david], when all else fails, be rigorous. Tell someone that it
is not o.k. to keep people busy with his complaints when he doesn't
know what he is talking about. This is *my* rejection of inpoliteness
and has nothing to do with "this group" in the first place. But I'm
not entirely sure I want to discuss about polite behaviour with
someone not using his full name.

Kay
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top