File: tutorial002.html

package info (click to toggle)
ocaml-doc 3.09-1
  • links: PTS
  • area: non-free
  • in suites: etch, etch-m68k
  • size: 10,428 kB
  • ctags: 4,963
  • sloc: ml: 9,244; makefile: 2,413; ansic: 122; sh: 49; asm: 17
file content (220 lines) | stat: -rw-r--r-- 7,926 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
            "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>

<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="hevea 1.06">
<TITLE>
 Streams and parsers
</TITLE>
</HEAD>
<BODY TEXT=black BGCOLOR=white>
<A HREF="tutorial001.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Up"></A>
<A HREF="tutorial003.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
<TR><TD BGCOLOR="#2de52d"><DIV ALIGN=center><TABLE>
<TR><TD><A NAME="htoc6"><B><FONT SIZE=6>Chapter&nbsp;2</FONT></B></A></TD>
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=6>Streams and parsers</FONT></B></TD>
</TR></TABLE></DIV></TD>
</TR></TABLE>
<A NAME="c:tutstrm"></A>
The first extension provided by Camlp4 is streams and parsers. A
stream is a value of the abstract type <CODE>'a Stream.t</CODE>. It is like
a list but where only the first element is available: to read the
second element you have to remove the first one from the stream. A
parser is a function of type <CODE>'a Stream.t -&gt; 'b</CODE> which makes a
kind of pattern matching inside a stream.<BR>
<BR>


<A NAME="toc5"></A><TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
<TR><TD><A NAME="htoc7"><B><FONT SIZE=5>2.1</FONT></B></A></TD>
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Streams</FONT></B></TD>
</TR></TABLE></DIV></TD>
</TR></TABLE><BR>
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
<TR><TD BGCOLOR="#7fff7f"><DIV ALIGN=center><TABLE>
<TR><TD><A NAME="htoc8"><B><FONT SIZE=4>2.1.1</FONT></B></A></TD>
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=4>Streams constructor</FONT></B></TD>
</TR></TABLE></DIV></TD>
</TR></TABLE><BR>
A first way to create a stream is to use the parentheses <CODE>[&lt;</CODE> and
<CODE>&gt;]</CODE>. There are two kinds of elements: simple elements prefixed
by a quote <CODE>'</CODE> and stream elements not prefixed by it. The stream
is composed of the list of the simple and stream elements read in
their order.<BR>
<BR>


Examples:
<PRE>
     [&lt; '3; '1; '4; '1; '5 &gt;]
</PRE>
is a stream of these integers.
<PRE>
     # let s = [&lt; '"hello"; '"world" &gt;];;
     # let t = [&lt; '"I"; '"say"; s; '"as"; '"an"; '"example" &gt;];;
</PRE>
The above stream <CODE>t</CODE> is the stream of the strings: "I", "say",
"hello", "world", "as", "an", "example".<BR>
<BR>


To look (destructively) inside a stream, you can use the function
<CODE>Stream.next</CODE>, removing the first element from the stream and
returning it.<BR>
<BR>


The streams are lazy values. You can create infinite streams, like
this one, the stream of all integers:
<PRE>
     # let rec f n = [&lt; 'n; f (n + 1) &gt;];;
     # let s = f 0;;
</PRE>
<TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
<TR><TD BGCOLOR="#7fff7f"><DIV ALIGN=center><TABLE>
<TR><TD><A NAME="htoc9"><B><FONT SIZE=4>2.1.2</FONT></B></A></TD>
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=4>Streams builders</FONT></B></TD>
</TR></TABLE></DIV></TD>
</TR></TABLE><BR>
A second way to create streams are the streams builders. They are:
<UL><LI><CODE>Stream.of_string</CODE>: returns the character stream of the
string given as parameter.<BR>
<BR>
<LI><CODE>Stream.of_channel</CODE>: returns the character stream of the
input channel.<BR>
<BR>
<LI><CODE>Stream.of_list</CODE>: returns the stream of the list elemnts.<BR>
<BR>
<LI><CODE>Stream.from</CODE>: given a function, returns the stream
composed of the values returned by the function. See the library
module <CODE>Stream</CODE> for details.</UL>
Warning: the streams created by these stream builders are much more
efficient than the one created by the stream constructors, but they
cannot be inserted in them.<BR>
<BR>
<A NAME="toc6"></A><TABLE CELLPADDING=0 CELLSPACING=0 WIDTH="100%">
<TR><TD BGCOLOR="#66ff66"><DIV ALIGN=center><TABLE>
<TR><TD><A NAME="htoc10"><B><FONT SIZE=5>2.2</FONT></B></A></TD>
<TD WIDTH="100%" ALIGN=center><B><FONT SIZE=5>Parsers</FONT></B></TD>
</TR></TABLE></DIV></TD>
</TR></TABLE><BR>
The parsers are functions to look inside the streams.<BR>
<BR>


A parser is introduced by the keyword <CODE>parser</CODE>. It is like the
<CODE>function</CODE> statement, but with stream patterns instead of
pattern. For example, the function <CODE>Stream.next</CODE> introduced in
the previous section is defined as:
<PRE>
     parser [&lt; 'x &gt;] -&gt; x
</PRE>
A parser can return with 3 different ways:
<UL><LI>Either by a normal value, indicating that a stream pattern
matched the beginning of the stream.<BR>
<BR>
<LI>Or by raising the exception <CODE>Stream.Failure</CODE>, indicating
that no first element of the patterns matched the stream; in this case
the stream had not been modified.<BR>
<BR>
<LI>Or by raising the exception <CODE>Stream.Error</CODE>, indicating that
a first element of a pattern matched the input stream, but the rest
did not.</UL>
Example:
<PRE>
     # let p = parser [&lt; '3; '1; '4 &gt;] -&gt; "hey";;
     # p [&lt; '3; '1; '4 &gt;];;
     string : "hey"
     # p [&lt; '3; '1; '4; '1; '5; '9 &gt;];;
     string : "hey"
     # p [&lt; '1; '1; '4 &gt;];;
     Exception: Stream.Failure
     # p [&lt; '3; '2; '4 &gt;];;
     Exception: Stream.Error ""
</PRE>
The exceptio <CODE>Stream.Error</CODE> has a string parameter. You can
specify which string, in the parser, after the stream pattern element
and the token <CODE>??</CODE>. For example:
<PRE>
     # let p =
         parser [&lt; '3; '1 ?? "1 expected"; '4 ?? "4 expected" &gt;] -&gt; "hey"
       ;;
</PRE>
Note that the first stream pattern element does not accept this
extension since the parser raises <CODE>Stream.Failure</CODE> if it is not
recognized.<BR>
<BR>


A parser can call another parser. You can specify that as a stream
pattern element with syntax:
<PRE>
     pattern = expression
</PRE>
Example, with a recursive call:
<PRE>
     # type tok = If | Then | Else | Let | In | Equal | Ident of int;;
     # let rec expr =
         parser
           [&lt; 'If; x = expr; 'Then; y = expr; 'Else; z = expr &gt;] -&gt; "if"
         | [&lt; 'Let; 'Ident x; 'Equal; x = expr; 'In; y = expr &gt;] -&gt; "let"
       ;;
</PRE>
Note that a parser is not a system of grammars. You cannot use left
recursion:
<PRE>
     (* BAD EXAMPLE! *)
     # let rec expr = parser [&lt; x = expr; 'Equal; y = expr &gt;] -&gt; x;;
</PRE>
Which would loop when called, exactly like a function would.<BR>
<BR>


And you cannot start two patterns with the same elements. Only the
first one would be applied:
<PRE>
     (* BAD EXAMPLE! *)
     # let rec expr =
         parser
           [&lt; 'If; x = expr; 'Then; y = expr; 'Else; z = expr &gt;] -&gt; "if"
         | [&lt; 'If; x = expr; 'Then; y = expr &gt;] -&gt; "ifnoelse"
       ;;
</PRE>
If you want to do that, you need to left factorize your rules:
<PRE>
     # let rec expr =
         parser
           [&lt; 'If; x = expr; 'Then; y = expr; v = expr_kont &gt;] -&gt; v
       and expr_kont =
         parser
           [&lt; 'Else; z = expr &gt;] -&gt; "if"
         | [&lt; &gt;] -&gt; "ifnoelse"
       ;;
</PRE>
or with an anonymous parser:
<PRE>
     # let rec expr =
         parser
           [&lt; 'If; x = expr; 'Then; y = expr;
              v =
                parser
                  [&lt; 'Else; z = expr &gt;] -&gt; "if"
                | [&lt; &gt;] -&gt; "ifnoelse" &gt;] -&gt; v
       ;;
</PRE>
<I><FONT COLOR=maroon>
<br>
For remarks about Camlp4, write to:
<img src="http://cristal.inria.fr/~ddr/images/email.jpg" alt=email align=top>
</FONT></I><HR>
<A HREF="tutorial001.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Up"></A>
<A HREF="tutorial003.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>