source: abnfparser/bap/scanner.l @ 405

Last change on this file since 405 was 405, checked in by julian.reschke@…, 12 years ago

add custom version of Bill Fenner's ABNF Parser (BAP)

File size: 8.3 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 yylineno = 1;
43int yycolumn = 0;
44int yyerrors = 0;
45extern int permissive;
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\<{proseval}[>\r\n]     {
98                        char *p;
99                        yycolumn += strlen(yytext);
100                        yylval.string = strdup(yytext + 1);
101                        p = &yylval.string[strlen(yylval.string) - 1];
102                        if (*p != '>') {
103                                mywarn(MYERROR, "unterminated prose-val");
104                                unput(*p);      /* put the cr or lf back */
105                        }
106                        *p = '\0';
107                        return PROSEVAL;
108                        }
109{rulename}              {
110                        /* record the indentation of the first rule name. */
111                        if (indent == -1)
112                                indent = yycolumn;
113                        yycolumn += strlen(yytext);
114                        yylval.string = strdup(yytext);
115                        return RULENAME;
116                        }
117%[Bb]{bit}+(-|\.\.){bit}+               {
118                        yycolumn += strlen(yytext);
119                        scanrange(yytext + 2, 2, &yylval.range);
120                        return BINVALRANGE;
121                        }
122%[Bb]{bit}+(\.{bit}+)*  {
123                        yycolumn += strlen(yytext);
124                        yylval.string = scanstr(yytext + 2, 2);
125                        return BINVAL;
126                        }
127%[Bb].                  { mywarn(MYERROR, "bad bit value");
128                          badchar = yytext[2]; BEGIN(SKIP); }
129%[Dd]{digit}+(-|\.\.){digit}+   {
130                        yycolumn += strlen(yytext);
131                        scanrange(yytext + 2, 10, &yylval.range);
132                        return DECVALRANGE;
133                        }
134%[Dd]{digit}+(\.{digit}+)*      {
135                        yycolumn += strlen(yytext);
136                        yylval.string = scanstr(yytext + 2, 10);
137                        return DECVAL;
138                        }
139%[Dd].                  { mywarn(MYERROR, "bad decimal value");
140                          badchar = yytext[2]; BEGIN(SKIP); }
141%[Xx]{hexdig}+(-|\.\.){hexdig}+ {
142                        yycolumn += strlen(yytext);
143                        scanrange(yytext + 2, 16, &yylval.range);
144                        return HEXVALRANGE;
145                        }
146%[Xx]{hexdig}+(\.{hexdig}+)*    {
147                        yycolumn += strlen(yytext);
148                        yylval.string = scanstr(yytext + 2, 16);
149                        return HEXVAL;
150                        }
151%[Xx].                  { mywarn(MYERROR, "bad hex value");
152                          badchar = yytext[2]; BEGIN(SKIP); }
153{digit}*\*{digit}*      {
154                        char *ep;
155
156                        yycolumn += strlen(yytext);
157                        yylval.range.lo = strtoul(yytext, &ep, 10);
158                        if (*ep != '*') {
159                            mywarn(MYERROR, "internal scanner error 1");
160                            yylval.range.hi = -1;
161                        } else {
162                            yylval.range.hi = strtoul(ep + 1, &ep, 10);
163                            if (*ep) {
164                                mywarn(MYERROR, "internal scanner error 2");
165                                yylval.range.hi = -1;
166                            } else if (yylval.range.hi == 0)
167                                yylval.range.hi = -1;
168                        }
169                        return REPEAT;
170                        }
171{digit}*#{digit}*       {
172                        char *ep;
173
174                        yycolumn += strlen(yytext);
175                        yylval.range.lo = strtoul(yytext, &ep, 10);
176                        if (*ep != '#') {
177                            mywarn(MYERROR, "internal scanner error 1");
178                            yylval.range.hi = -1;
179                        } else {
180                            yylval.range.hi = strtoul(ep + 1, &ep, 10);
181                            if (*ep) {
182                                mywarn(MYERROR, "internal scanner error 2");
183                                yylval.range.hi = -1;
184                            } else if (yylval.range.hi == 0)
185                                yylval.range.hi = -1;
186                        }
187                        return LIST;
188                        }
189{digit}+                {
190                        char *ep;
191
192                        yycolumn += strlen(yytext);
193                        yylval.range.hi = yylval.range.lo = strtoul(yytext, &ep, 10);
194                        if (*ep) {
195                            mywarn(MYERROR, "internal scanner error 3");
196                            yylval.range.hi = yylval.range.lo = 42;
197                        }
198                        return REPEAT;
199                        }
200=\/                     { yycolumn += 2; return EQSLASH; }
201({wsp}+|(;[^\r\n]*)|{mycrlf}{wsp}+)+    { char *p = yytext;
202                                while (*p) {
203                                        /* TO DO:
204                                         * deal with indent if we
205                                         * have one set - if a blank
206                                         * line or a comment is indented
207                                         * less than enough, we warn
208                                         * about it. */
209                                        if (*p == '\r') {
210                                                gotcr();
211                                                if (*(++p) == '\n')
212                                                        p++;
213                                                continue;
214                                        }
215                                        if (*p == '\n') {
216                                                gotcr();
217                                                if (*(++p) == '\r')
218                                                        p++;
219                                                continue;
220                                        }
221                                        p++;
222                                        yycolumn++;
223                                }
224                                /* If we don't know the indent yet, then just
225                                   ignore leading whitespace. */
226                                if (indent == -1)
227                                        continue;
228                                /* If there is more whitespace than
229                                   the initial indent, then tell the parser
230                                   about the leading whitespace. */
231                                if (yycolumn > indent)
232                                        return CWSP;
233                                if (yycolumn < indent) {
234                                        indent = yycolumn;
235                                        mywarn(MYERROR, "adjusting indentation");
236                                }
237                                /* Since we didn't have more whitespace than
238                                   indent, tell the parser it was just
239                                   a CR. */
240                                return CRLF; }
241{mycrlf}                { gotcr(); return CRLF; }
242[][()=/]                { yycolumn++; return yytext[0]; }
243\|                      { yycolumn++;
244                          if (!permissive) {
245                                badchar = yytext[0];
246                                BEGIN(SKIP);
247                          }
248                          return yytext[0]; }
249.                       { yycolumn++; badchar = yytext[0]; BEGIN(SKIP); }
250%%
251
252static void
253scanrange(char *p, int base, struct range *r)
254{
255        char *ep;
256
257        r->lo = strtoul(p, &ep, base);
258        if (*ep != '-' && *ep != '.') {
259                mywarn(MYERROR, "internal scanner error 4");
260                r->hi = r->lo;
261                return;
262        }
263        if (*ep == '.') {
264                if (!permissive) {
265                        badchar = '.';
266                        BEGIN(SKIP);
267                }
268                mywarn(MYERROR, "Ranges use \"-\", not \"..\".");
269                ep++;
270        }
271        r->hi = strtoul(ep + 1, &ep, base);
272        if (*ep) {
273                mywarn(MYERROR, "internal scanner error 5");
274        }
275        if (r->hi < r->lo) {
276                mywarn(MYERROR, "inverted range");
277        }
278        return;
279}
280
281static char *
282scanstr(char *p, int base)
283{
284        char *ep;
285        char buf[512];  /*XXX*/
286        char *b = buf;
287        int i;
288
289        do {
290                i = strtoul(p, &ep, base);
291                if (i > 255) {  /* XXX */
292                        mywarn(MYWARNING, "I can't handle this legal ABNF char value");
293                        i = 255;
294                }
295                if (i == 0) {
296                        mywarn(MYERROR, "This parser will truncate strings at %%x00");
297                }
298                *b++ = i;
299                p = ep + 1;
300        } while (*ep == '.');
301        if (*ep)
302                mywarn(MYERROR, "internal scanner error 6");
303        *b++ = '\0';
304        return strdup(buf);
305}
306
307static void
308gotcr(void)
309{
310        yylineno++;
311        yycolumn = 0;
312}
313
314void
315scanreset(void) {
316        yylineno = 0;
317        yycolumn = 0;
318        indent = -1;
319}
Note: See TracBrowser for help on using the repository browser.