8cf8b7d2c0d531b2973d55f13155c54265dba113
[enscript.git] / states / lex.l
1 %{
2 /*
3  * Lexer for states.
4  * Copyright (c) 1997-1998 Markku Rossi.
5  *
6  * Author: Markku Rossi <mtr@iki.fi>
7  */
8
9 /*
10  * This file is part of GNU enscript.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; see the file COPYING.  If not, write to
24  * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 /*
29  * $Id: lex.l,v 1.1.1.1 2003/03/05 07:25:52 mtr Exp $
30  */
31
32 #include "defs.h"
33 #include "gram.h"
34
35 static void eat_comment ();
36 static char *read_string ___P ((unsigned int *len_return));
37 static void read_regexp ___P ((Node *node));
38 %}
39
40 real    [+-]?[0-9]+\.[0-9]*|[+-]?\.[0-9]+
41 integer [+-]?[0-9]+
42 symbol  [a-zA-Z_][a-zA-Z_0-9]*|\$.
43
44 %%
45
46 "/*"            { eat_comment (); }
47 [ \t\r\f]       { ; }
48 \n              { linenum++; }
49
50 \"              { yylval.node = node_alloc (nSTRING);
51                   yylval.node->u.str.data
52                     = read_string (&yylval.node->u.str.len);
53                   return tSTRING;
54                 }
55
56 '[^\\]'         { yylval.node = node_alloc (nINTEGER);
57                   yylval.node->u.integer = yytext[1];
58                   return tINTEGER;
59                 }
60
61 '\\.'           { yylval.node = node_alloc (nINTEGER);
62                   switch (yytext[2])
63                     {
64                     case 'n':
65                       yylval.node->u.integer = '\n';
66                       break;
67
68                     case 't':
69                       yylval.node->u.integer = '\t';
70                       break;
71
72                     case 'v':
73                       yylval.node->u.integer = '\v';
74                       break;
75
76                     case 'b':
77                       yylval.node->u.integer = '\b';
78                       break;
79
80                     case 'r':
81                       yylval.node->u.integer = '\r';
82                       break;
83
84                     case 'f':
85                       yylval.node->u.integer = '\f';
86                       break;
87
88                     case 'a':
89                       yylval.node->u.integer = '\a';
90                       break;
91
92                     default:
93                       yylval.node->u.integer = yytext[2];
94                       break;
95                     }
96
97                   return tINTEGER;
98                 }
99
100 \/              { yylval.node = node_alloc (nREGEXP);
101                   read_regexp (yylval.node);
102                   return tREGEXP;
103                 }
104
105 "BEGIN"         { return tBEGIN; }
106 "END"           { return tEND; }
107 "div"           { return tDIV; }
108 "else"          { return tELSE; }
109 "extends"       { return tEXTENDS; }
110 "for"           { return tFOR; }
111 "if"            { return tIF; }
112 "local"         { return tLOCAL; }
113 "namerules"     { return tNAMERULES; }
114 "return"        { return tRETURN; }
115 "start"         { return tSTART; }
116 "startrules"    { return tSTARTRULES; }
117 "state"         { return tSTATE; }
118 "sub"           { return tSUB; }
119 "while"         { return tWHILE; }
120
121 "=="            { return tEQ; }
122 "!="            { return tNE; }
123 "<="            { return tLE; }
124 ">="            { return tGE; }
125 "&&"            { return tAND; }
126 "||"            { return tOR; }
127 "++"            { return tPLUSPLUS; }
128 "--"            { return tMINUSMINUS; }
129 "+="            { return tADDASSIGN; }
130 "-="            { return tSUBASSIGN; }
131 "*="            { return tMULASSIGN; }
132 "div="          { return tDIVASSIGN; }
133
134 {real}          { yylval.node = node_alloc (nREAL);
135                   yylval.node->u.real = atof (yytext);
136                   return tREAL;
137                 }
138 {integer}       { yylval.node = node_alloc (nINTEGER);
139                   yylval.node->u.integer = atoi (yytext);
140                   return tINTEGER;
141                 }
142 {symbol}        { yylval.node = node_alloc (nSYMBOL);
143                   yylval.node->u.sym = xstrdup (yytext);
144                   return tSYMBOL;
145                 }
146
147 .               { return yytext[0]; }
148
149 %%
150
151 static void
152 eat_comment ()
153 {
154   int c;
155
156   while ((c = input ()) != EOF)
157     {
158       if (c == '\n')
159         linenum++;
160       else if (c == '*')
161         {
162           c = input ();
163           if (c == '/')
164             /* All done. */
165             return;
166
167           if (c == EOF)
168             {
169               yyerror (_("error: EOF in comment"));
170               break;
171             }
172           unput (c);
173         }
174     }
175   yyerror (_("error: EOF in comment"));
176 }
177
178
179 int
180 yywrap ()
181 {
182   return 1;
183 }
184
185 static char *
186 read_string (len_return)
187      unsigned int *len_return;
188 {
189   char *buf = NULL;
190   char *buf2;
191   int buflen = 0;
192   int bufpos = 0;
193   int ch;
194   int done = 0;
195
196   while (!done)
197     {
198       ch = input ();
199       if (ch == '\n')
200         linenum++;
201
202       switch (ch)
203         {
204         case EOF:
205         unexpected_eof:
206           yyerror (_("error: EOF in string constant"));
207           done = 1;
208           break;
209
210         case '"':
211           done = 1;
212           break;
213
214         case '\\':
215           ch = input ();
216           switch (ch)
217             {
218             case 'n':
219               ch = '\n';
220               break;
221
222             case 't':
223               ch = '\t';
224               break;
225
226             case 'v':
227               ch = '\v';
228               break;
229
230             case 'b':
231               ch = '\b';
232               break;
233
234             case 'r':
235               ch = '\r';
236               break;
237
238             case 'f':
239               ch = '\f';
240               break;
241
242             case 'a':
243               ch = '\a';
244               break;
245
246             case EOF:
247               goto unexpected_eof;
248               break;
249
250             default:
251               if (ch == '0')
252                 {
253                   int i;
254                   int val = 0;
255
256                   for (i = 0; i < 3; i++)
257                     {
258                       ch = input ();
259                       if ('0' <= ch && ch <= '7')
260                         val = val * 8 + ch - '0';
261                       else
262                         {
263                           unput (ch);
264                           break;
265                         }
266                     }
267                   ch = val;
268                 }
269               break;
270             }
271           /* FALLTHROUGH */
272
273         default:
274           if (bufpos >= buflen)
275             {
276               buflen += 1024;
277               buf = (char *) xrealloc (buf, buflen);
278             }
279           buf[bufpos++] = ch;
280           break;
281         }
282     }
283
284   buf2 = (char *) xmalloc (bufpos + 1);
285   memcpy (buf2, buf, bufpos);
286   buf2[bufpos] = '\0';
287   xfree (buf);
288
289   *len_return = bufpos;
290
291   return buf2;
292 }
293
294
295 static void
296 read_regexp (node)
297      Node *node;
298 {
299   char *buf = NULL;
300   char *buf2;
301   int buflen = 0;
302   int bufpos = 0;
303   int ch;
304   int done = 0;
305
306   while (!done)
307     {
308       ch = input ();
309       switch (ch)
310         {
311         case EOF:
312         unexpected_eof:
313           yyerror (_("error: EOF in regular expression"));
314           done = 1;
315           break;
316
317         case '/':
318           done = 1;
319           break;
320
321         case '\\':
322           ch = input ();
323           switch (ch)
324             {
325             case '\n':
326               /* Line break. */
327               linenum++;
328               continue;
329               break;
330
331             case 'n':
332               ch = '\n';
333               break;
334
335             case 'r':
336               ch = '\r';
337               break;
338
339             case 'f':
340               ch = '\f';
341               break;
342
343             case 't':
344               ch = '\t';
345               break;
346
347             case '/':
348             case '\\':
349               /* Quote these. */
350               break;
351
352             case EOF:
353               goto unexpected_eof;
354               break;
355
356             default:
357               if (ch == '0')
358                 {
359                   int i;
360                   int val = 0;
361
362                   for (i = 0; i < 3; i++)
363                     {
364                       ch = input ();
365                       if ('0' <= ch && ch <= '7')
366                         val = val * 8 + ch - '0';
367                       else
368                         {
369                           unput (ch);
370                           break;
371                         }
372                     }
373                   ch = val;
374                 }
375               else
376                 {
377                   /* Pass it through. */
378                   unput (ch);
379                   ch = '\\';
380                 }
381               break;
382             }
383           /* FALLTHROUGH */
384
385         default:
386           if (bufpos >= buflen)
387             {
388               buflen += 1024;
389               buf = (char *) xrealloc (buf, buflen);
390             }
391           buf[bufpos++] = ch;
392           break;
393         }
394     }
395
396   /* Possible options. */
397   done = 0;
398   while (!done)
399     {
400       ch = input ();
401       switch (ch)
402         {
403         case 'i':
404           /* Case-insensitive regular expression. */
405           node->u.re.flags |= fRE_CASE_INSENSITIVE;
406           break;
407
408         default:
409           /* Unknown option => this belongs to the next token. */
410           unput (ch);
411           done = 1;
412           break;
413         }
414     }
415
416   buf2 = (char *) xmalloc (bufpos + 1);
417   memcpy (buf2, buf, bufpos);
418   buf2[bufpos] = '\0';
419   xfree (buf);
420
421   node->u.re.data = buf2;
422   node->u.re.len = bufpos;
423 }
424
425 \f
426 /*
427 Local variables:
428 mode: c
429 End:
430 */