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