source: abnfparser/bap/scanner.l

Last change on this file was 2749, checked in by julian.reschke@…, 5 years ago

bap: experimental support for RFC 7405

  • Property svn:eol-style set to native
File size: 9.1 KB
Line 
1%{
2/*
3 * Bill's ABNF parser.
4 * Copyright 2002-2007 William C. Fenner <fenner@fenron.com>
5 *  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the author nor the names of contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY WILLIAM C. FENNER ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WILLIAM C. FENNER OR HIS
23 * BROTHER B1FF BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
29 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30 * DAMAGE.
31 */
32
33#include "config.h"
34#include <stdlib.h>
35#include <string.h>
36#include "common.h"
37#include "y.tab.h"
38
39static const char rcsid[] =
40 "$Id: scanner.l,v 1.1 2008-05-28 12:01:58 jre Exp $";
41
42int yycolumn = 0;
43int yyerrors = 0;
44extern int permissive;
45extern int rfc7405;
46int indent = -1;
47
48char badchar;
49
50static void scanrange(char *, int, struct range *);
51static char *scanstr(char *, int);
52static void gotcr(void);
53
54%}
55
56bit             [01]
57digit           [0-9]
58hexdig          [0-9A-Fa-f]
59
60rulename        [A-Za-z][-0-9A-Za-z]*
61wsp             [ \t]
62
63/* *(%x20-21 / %x23-7E) */
64charval         [ !#-~]*
65
66/* *(%x20-3D / %x3F-7E) */
67proseval        [ -=?-~]*
68
69mycrlf  (\n\r|\r\n|\r|\n)
70
71/* %x may be a flex feature; %s works but sometimes results in
72 * confusing error messages */
73%x SKIP
74
75/* line number isn't quite being updated properly.
76   suspect unterminated charval and prosevals. */
77%%
78<SKIP>.*{mycrlf}        {       char q = (badchar == '\'') ? '"' : '\'';
79                                mywarn(MYERROR, "Illegal character %c%c%c - skipping to end of line", q, badchar, q);
80                                gotcr();
81                                BEGIN(INITIAL);
82                                return CRLF; }
83\"{charval}["\r\n]      {
84                        char *p;
85                        yycolumn += strlen(yytext);
86                        yylval.string = strdup(yytext + 1);
87                        p = &yylval.string[strlen(yylval.string) - 1];
88                        if (*p != '"') {
89                                mywarn(MYERROR, "unterminated char-val");
90                                unput(*p);      /* put the cr or lf back */
91                        }
92                        *p = '\0';
93                        if (*yylval.string == '\0')
94                                mywarn(MYWARNING, "zero-length char-val");
95                        return CHARVAL;
96                        }
97\%i\"{charval}["\r\n]   {
98      if (!rfc7405) {
99                                mywarn(MYERROR, "need to enable support for RFC 7405 using -Xrfc7405");
100        badchar = yytext[0];
101        BEGIN(SKIP);
102      }
103                        char *p;
104                        yycolumn += strlen(yytext);
105                        yylval.string = strdup(yytext + 3);
106                        p = &yylval.string[strlen(yylval.string) - 1];
107                        if (*p != '"') {
108                                mywarn(MYERROR, "unterminated char-val");
109                                unput(*p);      /* put the cr or lf back */
110                        }
111                        *p = '\0';
112                        if (*yylval.string == '\0')
113                                mywarn(MYWARNING, "zero-length char-val");
114                        return CHARVAL;
115                        }
116\%s\"{charval}["\r\n]   {
117      if (!rfc7405) {
118                                mywarn(MYERROR, "need to enable support for RFC 7405 using -Xrfc7405");
119        badchar = yytext[0];
120        BEGIN(SKIP);
121      }
122                        char *p;
123                        yycolumn += strlen(yytext);
124                        yylval.string = strdup(yytext + 3);
125                        p = &yylval.string[strlen(yylval.string) - 1];
126                        if (*p != '"') {
127                                mywarn(MYERROR, "unterminated char-val");
128                                unput(*p);      /* put the cr or lf back */
129                        }
130                        *p = '\0';
131                        if (*yylval.string == '\0')
132                                mywarn(MYWARNING, "zero-length char-val");
133                        return CHARVALCS;
134                        }
135\<{proseval}[>\r\n]     {
136                        char *p;
137                        yycolumn += strlen(yytext);
138                        yylval.string = strdup(yytext + 1);
139                        p = &yylval.string[strlen(yylval.string) - 1];
140                        if (*p != '>') {
141                                mywarn(MYERROR, "unterminated prose-val");
142                                unput(*p);      /* put the cr or lf back */
143                        }
144                        *p = '\0';
145                        return PROSEVAL;
146                        }
147{rulename}              {
148                        /* record the indentation of the first rule name. */
149                        if (indent == -1)
150                                indent = yycolumn;
151                        yycolumn += strlen(yytext);
152                        yylval.string = strdup(yytext);
153                        return RULENAME;
154                        }
155%[Bb]{bit}+(-|\.\.){bit}+               {
156                        yycolumn += strlen(yytext);
157                        scanrange(yytext + 2, 2, &yylval.range);
158                        return BINVALRANGE;
159                        }
160%[Bb]{bit}+(\.{bit}+)*  {
161                        yycolumn += strlen(yytext);
162                        yylval.string = scanstr(yytext + 2, 2);
163                        return BINVAL;
164                        }
165%[Bb].                  { mywarn(MYERROR, "bad bit value");
166                          badchar = yytext[2]; BEGIN(SKIP); }
167%[Dd]{digit}+(-|\.\.){digit}+   {
168                        yycolumn += strlen(yytext);
169                        scanrange(yytext + 2, 10, &yylval.range);
170                        return DECVALRANGE;
171                        }
172%[Dd]{digit}+(\.{digit}+)*      {
173                        yycolumn += strlen(yytext);
174                        yylval.string = scanstr(yytext + 2, 10);
175                        return DECVAL;
176                        }
177%[Dd].                  { mywarn(MYERROR, "bad decimal value");
178                          badchar = yytext[2]; BEGIN(SKIP); }
179%[Xx]{hexdig}+(-|\.\.){hexdig}+ {
180                        yycolumn += strlen(yytext);
181                        scanrange(yytext + 2, 16, &yylval.range);
182                        return HEXVALRANGE;
183                        }
184%[Xx]{hexdig}+(\.{hexdig}+)*    {
185                        yycolumn += strlen(yytext);
186                        yylval.string = scanstr(yytext + 2, 16);
187                        return HEXVAL;
188                        }
189%[Xx].                  { mywarn(MYERROR, "bad hex value");
190                          badchar = yytext[2]; BEGIN(SKIP); }
191{digit}*\*{digit}*      {
192                        char *ep;
193
194                        yycolumn += strlen(yytext);
195                        yylval.range.lo = strtoul(yytext, &ep, 10);
196                        if (*ep != '*') {
197                            mywarn(MYERROR, "internal scanner error 1");
198                            yylval.range.hi = -1;
199                        } else {
200                            yylval.range.hi = strtoul(ep + 1, &ep, 10);
201                            if (*ep) {
202                                mywarn(MYERROR, "internal scanner error 2");
203                                yylval.range.hi = -1;
204                            } else if (yylval.range.hi == 0)
205                                yylval.range.hi = -1;
206                        }
207                        return REPEAT;
208                        }
209{digit}*#{digit}*       {
210                        char *ep;
211
212                        yycolumn += strlen(yytext);
213                        yylval.range.lo = strtoul(yytext, &ep, 10);
214                        if (*ep != '#') {
215                            mywarn(MYERROR, "internal scanner error 1");
216                            yylval.range.hi = -1;
217                        } else {
218                            yylval.range.hi = strtoul(ep + 1, &ep, 10);
219                            if (*ep) {
220                                mywarn(MYERROR, "internal scanner error 2");
221                                yylval.range.hi = -1;
222                            } else if (yylval.range.hi == 0)
223                                yylval.range.hi = -1;
224                        }
225                        return LIST;
226                        }
227{digit}+                {
228                        char *ep;
229
230                        yycolumn += strlen(yytext);
231                        yylval.range.hi = yylval.range.lo = strtoul(yytext, &ep, 10);
232                        if (*ep) {
233                            mywarn(MYERROR, "internal scanner error 3");
234                            yylval.range.hi = yylval.range.lo = 42;
235                        }
236                        return REPEAT;
237                        }
238=\/                     { yycolumn += 2; return EQSLASH; }
239({wsp}+|(;[^\r\n]*)|{mycrlf}{wsp}+)+    { char *p = yytext;
240                                while (*p) {
241                                        /* TO DO:
242                                         * deal with indent if we
243                                         * have one set - if a blank
244                                         * line or a comment is indented
245                                         * less than enough, we warn
246                                         * about it. */
247                                        if (*p == '\r') {
248                                                gotcr();
249                                                if (*(++p) == '\n')
250                                                        p++;
251                                                continue;
252                                        }
253                                        if (*p == '\n') {
254                                                gotcr();
255                                                if (*(++p) == '\r')
256                                                        p++;
257                                                continue;
258                                        }
259                                        p++;
260                                        yycolumn++;
261                                }
262                                /* If we don't know the indent yet, then just
263                                   ignore leading whitespace. */
264                                if (indent == -1)
265                                        continue;
266                                /* If there is more whitespace than
267                                   the initial indent, then tell the parser
268                                   about the leading whitespace. */
269                                if (yycolumn > indent)
270                                        return CWSP;
271                                if (yycolumn < indent) {
272                                        indent = yycolumn;
273                                        mywarn(MYERROR, "adjusting indentation");
274                                }
275                                /* Since we didn't have more whitespace than
276                                   indent, tell the parser it was just
277                                   a CR. */
278                                return CRLF; }
279{mycrlf}                { gotcr(); return CRLF; }
280[][()=/]                { yycolumn++; return yytext[0]; }
281\|                      { yycolumn++;
282                          if (!permissive) {
283                                badchar = yytext[0];
284                                BEGIN(SKIP);
285                          }
286                          return yytext[0]; }
287.                       { yycolumn++; badchar = yytext[0]; BEGIN(SKIP); }
288%%
289
290static void
291scanrange(char *p, int base, struct range *r)
292{
293        char *ep;
294
295        r->lo = strtoul(p, &ep, base);
296        if (*ep != '-' && *ep != '.') {
297                mywarn(MYERROR, "internal scanner error 4");
298                r->hi = r->lo;
299                return;
300        }
301        if (*ep == '.') {
302                if (!permissive) {
303                        badchar = '.';
304                        BEGIN(SKIP);
305                }
306                mywarn(MYERROR, "Ranges use \"-\", not \"..\".");
307                ep++;
308        }
309        r->hi = strtoul(ep + 1, &ep, base);
310        if (*ep) {
311                mywarn(MYERROR, "internal scanner error 5");
312        }
313        if (r->hi < r->lo) {
314                mywarn(MYERROR, "inverted range");
315        }
316        return;
317}
318
319static char *
320scanstr(char *p, int base)
321{
322        char *ep;
323        char buf[512];  /*XXX*/
324        char *b = buf;
325        int i;
326
327        do {
328                i = strtoul(p, &ep, base);
329                if (i > 255) {  /* XXX */
330                        mywarn(MYWARNING, "I can't handle this legal ABNF char value");
331                        i = 255;
332                }
333                if (i == 0) {
334                        mywarn(MYERROR, "This parser will truncate strings at %%x00");
335                }
336                *b++ = i;
337                p = ep + 1;
338        } while (*ep == '.');
339        if (*ep)
340                mywarn(MYERROR, "internal scanner error 6");
341        *b++ = '\0';
342        return strdup(buf);
343}
344
345static void
346gotcr(void)
347{
348        yylineno++;
349        yycolumn = 0;
350}
351
352void
353scanreset(void) {
354        yylineno = 0;
355        yycolumn = 0;
356        indent = -1;
357}
Note: See TracBrowser for help on using the repository browser.