[REBOL] Re: Problems with parsing
From: brett:codeconscious at: 30-Nov-2001 11:41
Hi Peter,
> Any suggestions on how to make a parse rule for text
> NOT including a special pattern?
>
>Crystal clear?!?
Somewhat. It would be better to provide an example, because now I have to
show the solution *and* design an example :)
I have come across this sort of problem a few times and I thank Ladislav for
showing me a solution.
One example where you might do this is when you have a sub rule that might
consume
something needed
by an enclosing rule.
For my example, I'll parse a block rather than text but the concept still
applies. I want to parse the following block, and print
out every word, but if I encounter a "|" I'll print out the text
**********
:
my-block: [ the quick brown fox | jumped | over the lazy]
This next bit of code will not work. If you try it you will see that there
are no "*"s printed, instead you will see the "|":
single-word: [set item word! (print mold item)]
phrase: [some single-word]
parse my-block [ phrase some ['| (print "**********") phrase] ]
The thing to note is that | is a word too. Therefore the "|" is "consumed"
by the rule called SINGLE-WORD. So one way
to solve this is to give SINGLE-WORD some indigestion (make it fail) when it
encounters a "|". To do this I will use a dynamic rule - a rule that is
modified as parse is executing.
To force a rule to fail, make sure it cannot match anything any more. A way
to ensure this is to skip past the end of the input. This next rule is
guaranteed to fail every time:
always-fails: [to end skip]
Using this I now wrap SINGLE-WORD with a rule I call WORD-EXCEPT-BAR. The
purpose of this new rule is to fail if it finds the "|" word otherwise it
goes ahead and runs SINGLE-WORD. I also need to modify PHRASE to call
WORD-EXCEPT-BAR: The dynamic rule I mentioned earlier is called WEB. Here
are rules with the complex one split over multiple lines to improve
readability:
phrase: [some word-except-bar]
word-except-bar: [
[
'| (web: :always-fails) | (web: :single-word)
]
web
]
To finish off I'll create a function to call parse with the correct rule and
wrap the whole lot in an object just to be tidy:
word-parsing-object: context [
always-fails: [to end skip]
single-word: [set item word! (print mold item)]
word-except-bar: [ ['| (web: :always-fails) | (web: :single-word)]
web ]
phrase: [some word-except-bar]
set 'parse-words func[ a-block [block!] ] [
parse my-block [ phrase some ['| (print "**********") phrase] ]
]
]
Here is a test run:
>> parse-words [the quick brown fox | jumped | over the lazy]
the
quick
brown
fox
**********
jumped
**********
over
the
lazy
== true
HTH
Brett.